Merge remote-tracking branch 'origin/master'

This commit is contained in:
zhangkaihuai
2024-06-24 01:06:15 +08:00
92 changed files with 3962 additions and 12301 deletions

View File

@@ -25,9 +25,9 @@ steps:
- npm -v
- mkdir -p ./node_modules
- export NODE_MODULES_PATH=`pwd`/node_modules
# - npm config set registry https://registry.npmmirror.com
#- set NODE_OPTIONS=--openssl-legacy-provider
# - npm install
# - npm config set registry https://registry.npmmirror.com
# - set NODE_OPTIONS=--openssl-legacy-provider
# - npm install
- npm run build
- ls /app/build/$DRONE_REPO_NAME/
- echo $NODE_MODULES_PATH

11348
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,7 @@
"d3": "^7.8.5",
"echarts": "^5.4.2",
"element-plus": "^2.6.0",
"file-saver": "^2.0.5",
"highlight.js": "9.18.5",
"jquery": "^3.6.0",
"js-cookie": "^3.0.5",
@@ -30,7 +31,9 @@
"vue-codemirror": "^6.1.1",
"vue-json-viewer": "^3.0.4",
"vue-router": "^4.1.6",
"vuedraggable": "^4.1.0"
"vuedraggable": "^4.1.0",
"xlsx": "^0.18.5",
"xlsx-style-vite": "^0.0.2"
},
"devDependencies": {
"@codemirror/lang-java": "^6.0.1",

View File

@@ -13,6 +13,19 @@ export const getAllocationDetail = (allocationId) => {
method: "get"
});
};
export const getAllocationDetails = (allocationId) => {
return request({
url: `/workflow/mosr/cost/allocation/usr/detail/${allocationId}`,
method: "get"
});
};
export const getAllocationSummaryDetails = (params) => {
return request({
url: '/workflow/mosr/cost/allocation/collect',
method: "get",
params:params
});
};
export const getAllocationProcess = () => {
return request({
url: '/workflow/mosr/cost/allocation/process',

View File

@@ -7,6 +7,7 @@ export const getCodeImg = () => {
})
}
export const login = (data) => {
return request({
url: '/auth/login',
@@ -14,6 +15,12 @@ export const login = (data) => {
data
})
}
export const switchAccount = (userId) => {
return request({
url: `/auth/switch/account/${userId}`,
method: 'post',
})
}
export const getUserInfo = () => {
return request({

View File

@@ -15,3 +15,17 @@ export const uploadFileList = (data) => {
data: data
});
};
export const searchImplementationFileList = (params) => {
return request({
url: '/workflow/mosr/attachment/implementation/list',
method: "get",
params: params
});
};
export const switchAttachmentState = (data) => {
return request({
url: '/workflow/mosr/project/filing/attachment/switch',
method: "post",
data
});
};

View File

@@ -1,147 +1,174 @@
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
//项目立项
export const getApplyProcess = (projectId) => {
return request({
url: `/workflow/mosr/project/approval/initiation/process/${projectId}`,
method: "get"
});
return request({
url: `/workflow/mosr/project/approval/initiation/process/${projectId}`,
method: "get"
});
};
export const projectApply = (data) => {
return request({
url: '/workflow/mosr/project/approval/initiation/apply',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/approval/initiation/apply',
method: "post",
data: data
});
};
export const getApplyDetail = (ProjectId) => {
return request({
url: `/workflow/mosr/project/approval/info/${ProjectId}`,
method: "get"
});
return request({
url: `/workflow/mosr/project/approval/info/${ProjectId}`,
method: "get"
});
};
export const resubmitApply = (data) => {
return request({
url: '/workflow/mosr/project/approval/initiation/resubmit',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/approval/initiation/resubmit',
method: "post",
data: data
});
};
export const getInitiationAttachment = (params) => {
return request({
url: '/workflow/mosr/project/approval/attachments',
method: "get",
params:params
});
return request({
url: '/workflow/mosr/project/approval/attachments',
method: "get",
params: params
});
};
//项目实施
export const getCheckDetail = (projectId) => {
return request({
url: `/workflow/mosr/project/implementation/info/${projectId}`,
method: "get"
});
return request({
url: `/workflow/mosr/project/implementation/info/${projectId}`,
method: "get"
});
};
export const resubmitCheck = (data) => {
return request({
url: '/workflow/mosr/project/implementation/resubmit',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/implementation/resubmit',
method: "post",
data: data
});
};
export const projectCheck = (data) => {
return request({
url: '/workflow/mosr/project/implementation/initiation/check',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/implementation/initiation/check',
method: "post",
data: data
});
};
export const getProjectCheckProcess = (projectId) => {
return request({
url: `/workflow/mosr/project/implementation/process/${projectId}`,
method: "get"
});
return request({
url: `/workflow/mosr/project/implementation/process/${projectId}`,
method: "get"
});
};
export const addLedger = (data) => {
return request({
url: '/workflow/mosr/expense/ledger',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/expense/ledger',
method: "post",
data: data
});
};
export const getTags = (projectId) => {
return request({
url: `/workflow/mosr/attachment/option/${projectId}`,
method: "get"
});
return request({
url: `/workflow/mosr/attachment/option/${projectId}`,
method: "get"
});
};
export const getPhaseProcess = () => {
return request({
url: '/workflow/phase/change/process',
method: "get"
});
return request({
url: '/workflow/phase/change/process',
method: "get"
});
};
export const submitPhaseChange = (data) => {
return request({
url: '/workflow/phase/change',
method: "post",
data: data
});
return request({
url: '/workflow/phase/change',
method: "post",
data: data
});
};
export const getPhaseDetail = (projectId) => {
return request({
url: `/workflow/phase/change/info/${projectId}`,
method: "get"
});
return request({
url: `/workflow/phase/change/info/${projectId}`,
method: "get"
});
};
export const getPhaseForm = (projectId) => {
return request({
url: `/workflow/phase/change/from/${projectId}`,
method: "get"
});
return request({
url: `/workflow/phase/change/from/${projectId}`,
method: "get"
});
};
export const resubmitPhaseForm = (data) => {
return request({
url: '/workflow/phase/change/resubmit',
method: "post",
data: data
});
return request({
url: '/workflow/phase/change/resubmit',
method: "post",
data: data
});
};
//项目归档
export const getConclusionDetail = (ProjectId) => {
return request({
url: `/workflow/mosr/project/filing/info/${ProjectId}`,
method: "get"
});
return request({
url: `/workflow/mosr/project/filing/info/${ProjectId}`,
method: "get"
});
};
export const resubmitConclusion = (data) => {
return request({
url: '/workflow/mosr/project/filing/resubmit',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/filing/resubmit',
method: "post",
data: data
});
};
export const projectConclusion = (data) => {
return request({
url: '/workflow/mosr/project/filing/project/entry',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/filing/project/entry',
method: "post",
data: data
});
};
export const getProjectConclusionProcess = () => {
return request({
url: '/workflow/mosr/project/filing/process',
method: "get"
});
return request({
url: '/workflow/mosr/project/filing/process',
method: "get"
});
};
//获取前置流程
export const getPreProcess= () => {
return request({
url: '/workflow/details/pre/process',
method: "get"
});
export const getPreProcess = () => {
return request({
url: '/workflow/details/pre/process',
method: "get"
});
};
export const updateLedger = (data) => {
return request({
url: '/workflow/mosr/expense/ledger/replenishment',
method: "post",
data: data
});
};
export const searchUpdateLedgerData = (projectId) => {
return request({
url: `/workflow/mosr/expense/ledger/${projectId}`,
method: "get"
});
};
export const exportExcel = (data) => {
return axios.post(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/project/implementation/export`,
data, {
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};

View File

@@ -50,4 +50,4 @@ export const getMenuOptRole = (roleId) => {
url: '/admin/menu/option/role/'+roleId,
method: 'get'
})
}
}

View File

@@ -15,6 +15,12 @@ export const getSubCompOpt = () => {
method: 'get'
})
}
export const getUserAccount = () => {
return request({
url: `/admin/mosr/user/account/list`,
method: 'get'
})
}
// 查询角色信息
export const getRolesOpt = () => {
@@ -49,7 +55,7 @@ export const getUserDetail = (userId) => {
// 操作
export const operate = (data, type) => {
console.log(type ,'type');
// console.log(type ,'type');
if(data.userId && type !== '0') return editUser(data)
else if(type == '0') return editUserOA(data)
return addUser(data)

View File

@@ -22,7 +22,7 @@ export function getDepartmentTree() {
method: 'get'
})
}
export function getMosrDept(params) {
export function getMosrUser(params) {
return request({
url: '/admin/mosr/user/choose',
method: 'get',

View File

@@ -7,9 +7,11 @@
<el-button type="primary" link @click="handleDownload(singleFile)" style="font-size: 16px">
{{ singleFile ? singleFile?.originalFileName : formData.singleFile?.originalFileName }}
</el-button>
<el-button type="danger" link @click="deleteSingleFile(singleFile?singleFile:formData.singleFile,1)">删除</el-button>
<el-button type="danger" link @click="deleteSingleFile(singleFile?singleFile:formData.singleFile,1)">删除
</el-button>
</template>
<template v-else-if="!preview||JSON.stringify(singleFile) == '{}'||singleFile==null||formData.singleFile==null">
<template
v-else-if="!preview||JSON.stringify(singleFile) == '{}'||singleFile==null||formData.singleFile==null">
<file-upload @getFile="getAttachment" :showFileList="showFileList" :multiple="false" :maxSize="1"
:disabled="isSingleFile" @delete="deleteAttachment"/>
</template>
@@ -97,7 +99,7 @@ const tableConfig = reactive({
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile){
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
@@ -116,7 +118,7 @@ const tableConfig = reactive({
{
row.newFile || props.preview || !props.preview ?
<popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
perm={['mosr:requirement:del']}
// perm={['']}
onDelete={() => handleDelete(row)}/>
: ''
}
@@ -137,7 +139,7 @@ watch(() => props.showTable, (newVal) => {
props.showTable = newVal
}, {deep: true})
watch(() => props.formData.fileList, (newVal) => {
console.log('newVal-fileList', newVal)
// console.log('newVal-fileList', newVal)
if (props.preview) {
newVal?.forEach(item => {
allFileList.value.push(item)
@@ -145,7 +147,7 @@ watch(() => props.formData.fileList, (newVal) => {
}
}, {deep: true})
watch(() => props.otherFileList, (newVal) => {
console.log('newotherFileList', newVal,props.formData)
// console.log('newotherFileList', newVal, props.formData)
if (props.preview) {
if (props.formData.fileList === null || props.formData.fileList.length === 0) {
allFileList.value = newVal
@@ -159,7 +161,7 @@ watch(() => props.otherFileList, (newVal) => {
}
}, {deep: true})
watch(() => props.formData.singleFile, (newVal) => {
console.log('singleFile', newVal)
// console.log('singleFile', newVal)
singleFile.value = newVal
}, {deep: true})
watch(() => isSingleFile.value, (newVal) => {

View File

@@ -0,0 +1,105 @@
<template>
<el-button color="#DED0B2" style="float: right;margin: 0 10px 10px 0" @click="exportTable">导出</el-button>
<el-table ref="table" :data="tableData" style="width: 100%;height: 479px" :show-summary="true" border
:summary-method="getSummaries" v-loading="loading" :header-cell-style="{background:'#f5f7fa'}">
<el-table-column type="index" label="序号" align="center" width="60"/>
<el-table-column prop="projectName" label="项目名称" align="center"/>
<el-table-column prop="projectCost" label="费用性质" align="center">
<template #default="scope">
<div v-if="scope.row.projectCost !== null">
<Tag dictType="project_cost" :value="scope.row.projectCost"/>
</div>
<div v-else>--</div>
</template>
</el-table-column>
<el-table-column prop="researchStage" label="项目阶段" align="center">
<template #default="scope">
<div
v-if="scope.row.researchStage !== null && scope.row.researchStage !== null && scope.row.researchStage !== undefined">
<Tag dictType="research_stage" :value="scope.row.researchStage"/>
</div>
<div v-else>--</div>
</template>
</el-table-column>
<el-table-column prop="afterTax" label="分摊金额" align="center">
<template #default="scope">
<div v-if="scope.row.afterTax !== null">
<!-- {{ toThousands(scope.row.afterTax) }}-->
{{ scope.row.afterTax }}
</div>
</template>
</el-table-column>
</el-table>
</template>
<script setup>
import {toThousands} from '@/utils/changePrice.js'
import {exportExcel} from "@/utils/export-excel";
import {getAllocationSummaryDetails} from "@/api/expense-manage";
const tableData = ref([{
id: '12987122',
name: 'Tom',
amount1: '234',
amount2: '3.2',
amount3: 10,
},
{
id: '12987123',
name: 'Tom',
amount1: '165',
amount2: '4.43',
amount3: 12,
}])
const loading = ref(false)
const table = ref()
const route = useRoute()
const getSummaries = (param) => {
const {columns, data} = param
const sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '小计'
} else if (index === 4) {
const values = data.map((item) => Number(item[column.property]))
if (!values.every((value) => Number.isNaN(value))) {
sums[index] = `${values.reduce((prev, curr) => {
const value = Number(curr)
if (!Number.isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)}`
// sums[index] = toThousands(sums[index])
} else {
sums[index] = '-'
}
}
})
return sums
}
const exportTable = () => {
const $e = table.value.$el
let $table = $e.querySelector('.el-table__fixed')
if (!$table) {
$table = $e
}
exportExcel($table, (5 + (Object.keys(tableData.value[0]).length - 5) * 5), "四川省国有资产经营投资管理有限责任公司科技创新项目费用分摊表",2)
}
const init = () => {
loading.value = true
let params = {
allocationId: route.query.id
}
getAllocationSummaryDetails(params).then(res => {
tableData.value = res.data
loading.value = false
})
}
init()
</script>
<style scoped>
</style>

View File

@@ -29,7 +29,8 @@
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram" :operation-list="data.operationList"
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" :id-name="idName?idName:type"/>
</div>
@@ -97,9 +98,10 @@ const schema = computed(() => {
component: () => (
<div>
{
props.formData.preProcess?
<span><a target="_blank" style={{color: '#409EFF', cursor: 'pointer'}} href={props.formData.preProcessBaseUrl + props.formData.preProcess.requestId}>{props.formData.preProcess.requestName}</a> </span> :
<span>{'--'}</span>
props.formData.preProcess ? props.formData.preProcess.map(item => {
return <span><a target="_blank" style={{color: '#409EFF', cursor: 'pointer'}}
href={props.formData.preProcessBaseUrl + item.requestId}>{item.requestName}</a> </span>
}) : <span>{'--'}</span>
}
</div>
)
@@ -138,9 +140,10 @@ const schema = computed(() => {
component: () => (
<div>
{
props.formData.preProcess?
<span><a target="_blank" style={{color: '#409EFF', cursor: 'pointer'}} href={props.formData.preProcessBaseUrl + props.formData.preProcess.requestId}>{props.formData.preProcess.requestName}</a> </span> :
<span>{'--'}</span>
props.formData.preProcess ? props.formData.preProcess.map(item => {
return <span><a target="_blank" style={{color: '#409EFF', cursor: 'pointer'}}
href={props.formData.preProcessBaseUrl + item.requestId}>{item.requestName}</a> </span>
}) : <span>{'--'}</span>
}
</div>
)

View File

@@ -2,26 +2,31 @@
<div v-loading="loading">
<el-form :model="formData" label-width="auto">
<el-row>
<el-col :span="12" v-if="type==='singleDetail'">
<el-col :span="6" v-if="type==='singleDetail'">
<el-form-item label="征集名称">
<span>{{ formData.requirementName }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-col :span="6">
<el-form-item label="征集类型">
<span>{{ formData.collectType }}</span>
</el-form-item>
</el-col>
<el-col :span="12" v-if="type==='singleDetail'">
<el-form-item label="所属公司">
<span>{{ formData.companyIds }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-col :span="6">
<el-form-item label="截止时间">
<span>{{ formData.deadline }}</span>
</el-form-item>
</el-col>
<el-col :span="24" v-if="type==='singleDetail'">
<el-form-item label="所属公司">
<span :class="showExpendClass(showMoreCompany,formData.companyIds)">{{
getCompanyName(formData.companyIds)
}}</span>
<div style="color: #2a99ff;text-align: center;width: 100%;font-size: 15px;cursor: pointer"
@click="handleExpend">{{ showExpendText }}
</div>
</el-form-item>
</el-col>
<el-col :span="24" v-if="formData.isSpecialFund">
<el-form-item label="专项资金">
<span>{{ formData.specialFund }}</span>
@@ -84,6 +89,8 @@ import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.v
import {downloadFile} from "@/api/project-demand";
const emit = defineEmits(['update:value'])
const showExpendText = ref('')
const showMoreCompany = ref(false)
const props = defineProps({
formData: {
type: Array,
@@ -127,7 +134,26 @@ const _value = computed({
emit("update:value", val);
}
})
const getCompanyName = (data) => {
if (data) {
return data.join('')
}
}
const handleExpend = () => {
showMoreCompany.value = !showMoreCompany.value;
showExpendClass(showMoreCompany.value, props.formData.companyIds)
}
const showExpendClass = (showMoreCompany, data) => {
if (!showMoreCompany) {
if (data && data.length > 14) {
showExpendText.value = '展开'
return 'company-style'
}
} else {
showExpendText.value = '收缩'
return ''
}
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
@@ -152,4 +178,15 @@ watch(() => props.processViewer, (newVal) => {
:deep(.el-empty__description) {
margin-top: 0;
}
.company-style {
//width: 98%;
min-height: 30px;
max-height: 60px;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
}
</style>

View File

@@ -10,15 +10,15 @@
<el-button @click="getList()">搜索</el-button>
</template>
</el-input>
<el-button v-if="isChooseAll" @click="chooseAll">全选</el-button>
<el-button v-else @click="cancelAll">不全选</el-button>
<fvCheckbox style="margin-left: 10px" :options="checkOptions" v-model="checkList" @change="checkBoxChange"/>
<!-- 人员选择 -->
<el-empty :image-size="100" description="似乎没有数据" v-show="dataList.length === 0"/>
<el-scrollbar style="height:87%;">
<div class="tree">
<el-tree :data="dataList" ref="tree" :props="defaultProps" empty-text="" node-key="value"
default-expand-all :show-checkbox="showCheckbox" highlight-current :default-checked-keys="defaultChecked"
:check-strictly="true" @node-click="(node,check)=>handle(node,check)"
:show-checkbox="showCheckbox" highlight-current default-expand-all
:default-checked-keys="defaultChecked" :disabled="disabled"
:check-strictly="!checkStrictly" @node-click="(node,check)=>handle(node,check)"
@check-change="handleChange" :filter-node-method="filterNode">
<template #default="{ node, data }">
<div class="tree-node">
@@ -40,8 +40,7 @@
<el-empty :image-size="100" description="请点击左侧列表选择数据" v-show="selectList.length === 0"/>
<div v-for="(selectItem, selectIndex) in selectList" :key="selectIndex" class="org-item">
{{ selectItem.label }}
<el-icon @click="noSelected(selectItem)" size="20" style="margin-left: 10px;cursor: pointer;"
v-if="showCheckbox===false">
<el-icon @click="noSelected(selectItem)" size="20" style="margin-left: 10px;cursor: pointer;">
<CircleClose/>
</el-icon>
</div>
@@ -59,6 +58,20 @@
import {ElMessageBox} from "element-plus";
import {getSubCompOpt} from "@/api/user/user";
const checkList = ref(['1'])
const checkStrictly = ref(false)
const isExpand = ref('展开')
const expandedKeys = ref(['-1']);
const checkOptions = ref([
{
label: isExpand.value,
value: '1'
},
{
label: '父子联动',
value: '2'
},
])
const props = defineProps({
value: {
type: Array,
@@ -75,9 +88,7 @@ const props = defineProps({
type: Boolean
}
});
const radio = ref(0);
const isChooseAll = ref(true);
const chooseId = ref(0);
let selectItem = reactive({
type: -1,
value: "0"
@@ -90,12 +101,11 @@ const filterText = ref("");
const dataList = ref([]);
const defaultChecked = ref([]);
const tree = ref([]);
const isSearch = ref(false);
const expandedKeys = ref([]);
const defaultProps = {
value: "value",
label: "label",
children: "children"
children: "children",
disabled: "disabled",
};
const emit = defineEmits();
const _value = computed({
@@ -110,25 +120,48 @@ const _value = computed({
watch(() => filterText.value, (newVal) => {
tree.value.filter(newVal);
});
const matterTree=(list)=>{
list.forEach(item=>{
tree.value.setChecked(item,true)
if(item.children!==undefined){
const checkBoxChange = (val) => {
checkStrictly.value = val.includes('2')
let nodes = tree.value.store.nodesMap
if (val.includes('1')) {
for (const node in nodes) {
nodes[node].expanded = true;
}
isExpand.value = '折叠'
} else {
for (const node in nodes) {
nodes[node].expanded = false;
}
isExpand.value = '展开'
}
}
const matterTree = (list, flag) => {
list.forEach(item => {
if (!flag&&item.value!==-1) {
tree.value.setChecked(item, false)
}
if (item.children !== undefined) {
matterTree(item.children)
}
})
}
const cancelAll=()=>{
isChooseAll.value=true
tree.value.setCheckedNodes([])
}
const chooseAll=()=>{
isChooseAll.value=false
matterTree(dataList.value)
}
// const cancelAll = () => {
// isChooseAll.value = true
// tree.value.setCheckedNodes([])
// }
// const chooseAll = () => {
// isChooseAll.value = false
// matterTree(dataList.value)
// }
const getList = () => {
getSubCompOpt().then(res => {
dataList.value = res.data;
dataList.value = [
{
label: "全选",
value: -1,
children: res.data
}
]
});
};
@@ -142,49 +175,49 @@ const filterNode = (value, data) => {
const show = () => {
//用于弹开部门选择
visible.value = true;
selectList.value=_value.value
defaultChecked.value=_value.value.map(item=>item.value)
selectList.value = _value.value
defaultChecked.value = _value.value.map(item => item.value)
getList()
};
const handleChange = (data, checked) => {
console.log('data, checked',data, checked)
// 左侧有选择框
// if (props.showCheckbox) {
// 左侧有选择框 + 多选
if (props.multiple) {
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === data.value) {
selectList.value.splice(i, 1);
break;
}
}
if (checked) {
// if (data.children === undefined) {
selectList.value.push(data);
// }
} else if (data === "1") {
tree.value.setCheckedKeys([]);
selectList.value = [];
}
} else {// 左侧有选择框 + 单选
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === data.value) {
selectList.value.splice(i, 1);
break;
}
}
if (checked) {
tree.value.setCheckedNodes([data]);
// this.$refs.tree.setCheckedKeys([]);
selectList.value = [data];
} else if (data === "1") {
selectList.value = [];
tree.value.setCheckedKeys([]);
if (data.value == -1&&checked) {
// tree.value.setCheckedNodes(['-1'])
matterTree(dataList.value, false)
// return;
}
// 左侧有选择框 + 多选
if (props.multiple) {
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === data.value) {
selectList.value.splice(i, 1);
break;
}
}
// }
if (checked) {
// if (data.children === undefined) {
selectList.value.push(data);
// }
} else if (data === "1") {
tree.value.setCheckedKeys([]);
selectList.value = [];
}
} else {// 左侧有选择框 + 单选
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === data.value) {
selectList.value.splice(i, 1);
break;
}
}
if (checked) {
tree.value.setCheckedNodes([data]);
selectList.value = [data];
} else if (data === "1") {
selectList.value = [];
tree.value.setCheckedKeys([]);
}
}
};
const handle = (node, check) => {
if (check.isLeaf !== false) {
@@ -209,8 +242,8 @@ const noSelected = (selectItem) => {
//左侧无选择框时,右侧显示×
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === selectItem.value) {
tree.value.setChecked(selectList.value[i].value, false);
selectList.value.splice(i, 1);
tree.value.setCheckedKeys(i);
break;
}
}

View File

@@ -1,144 +1,248 @@
<template>
<div>
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
<fvTable ref="tableIns" :tableConfig="tableConfig">
<template #empty>
<el-empty description="暂无数据"/>
<el-button color="#DED0B2" style="float: right;margin: 0 10px 10px 0" @click="exportTable">导出</el-button>
<el-table ref="reportTable" :data="tableData" style="width: 100%;height: 479px"
:span-method="objectSpanMethod" v-loading="loading">
<!-- <el-table-column label="四川省国有资产经营投资管理有限责任公司-->
<!-- 科技创新项目人工成本分摊明细表" align="center">-->
<el-table-column v-for="column in columnInfo" :prop="column.prop" :label="column.label" align="center"
:fixed="(!column.children) ? ((column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') ? 'right' : 'left') : false"
:width="(column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') ? 160:130">
<template #default="scope">
<template v-if="column.children">
<el-table-column v-for="childColumn in column.children"
:prop="column.prop + '.'+ childColumn.prop"
:label="childColumn.label"
:width="childColumn.prop === 'subtotal' ? 160 : 130">
<template #default="columnScope">
<template v-if="(tableData.length -1) !== columnScope.$index">
{{
columnScope.row[column.prop][childColumn.prop] ? columnScope.row[column.prop][childColumn.prop] : '/'
}}
</template>
<template v-else>
{{ columnScope.row[column.prop][childColumn.prop] }}
</template>
</template>
</el-table-column>
</template>
<template v-else>
<!--分摊金额合计与分摊金额总计计算-->
<template
v-if="(column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') && (tableData.length -1) !== scope.$index">
{{ getTotalSeparation(scope.row, column.prop) }}
</template>
<template
v-else-if="(tableData.length -1) === scope.$index && (column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost')">
{{ getTotalSummary(scope.row, column.prop) }}
</template>
<template v-else>
{{ scope.row[column.prop] }}
</template>
</template>
</template>
</fvTable>
</div>
</el-table-column>
<!-- </el-table-column>-->
</el-table>
</template>
<script setup lang="jsx">
import {getResearchUser} from "@/api/expense-manage";
import {getResearchUser, getAllocationDetails} from "@/api/expense-manage";
import {exportExcel} from "@/utils/export-excel";
const route = useRoute()
const searchConfig = reactive([
{
label: '项目名称',
prop: 'projectName',
component: 'el-input',
props: {
placeholder: '请输入项目名称查询',
clearable: true,
filterable: true,
checkStrictly: true
}
},
{
label: '姓名',
prop: 'researchPersonnel',
component: 'el-input',
props: {
placeholder: '请输入姓名查询',
clearable: true,
filterable: true,
checkStrictly: true
}
},
// {
// label: '起始时间',
// prop: 'time',
// component: 'el-date-picker',
// props: {
// placeholder: '请选择起始时间',
// clearable: true,
// },
// colProps: {}
// },
])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'projectName',
label: '项目名称',
align: 'center'
},
{
prop: 'researchPersonnel',
label: '研发人员',
align: 'center',
currentRender:({row})=>{
return <span>{getResearchName(row.researchPersonnel)}</span>
}
},
{
prop: 'wagesPayable',
label: '应发工资',
align: 'center'
},
{
prop: 'performance',
label: '绩效',
align: 'center'
},
{
prop: 'reserveFund',
label: '公积金',
align: 'center'
},
{
prop: 'socialSecurity',
label: '社保',
align: 'center'
},
{
prop: 'annuity',
label: '年金',
align: 'center'
},
{
prop: 'workday',
label: '工作日(天)',
align: 'center'
},
{
prop: 'researchDuration',
label: '研发时长(天)',
align: 'center'
},
],
api:'/workflow/mosr/cost/allocation/usr',
params:{
allocationId:route.query.id
}
})
const tableIns = ref()
const reportTable = ref({});
const columnInfo = ref([])
const monthConcat = new Map()
const tableData = ref([])
const loading = ref(false)
const researchOptions = ref([])
const objectSpanMethod = ({row, column, rowIndex, columnIndex}) => {
if (columnIndex === 0) {
if (monthConcat.has(rowIndex)) {
return {
rowspan: monthConcat.get(rowIndex),
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
} else {
let length = Object.keys(row).length
console.log(length)
if (length > 5) {
if (concatColumn(columnIndex, length, rowIndex)) {
if (rowIndex % 5 === 0) {
return {
rowspan: 5,
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
}
}
}
}
const getTotalSeparation = (row, prop) => {
let totalSeparation = 0.00
for (let key of Object.keys(row)) {
if (key.startsWith('personInfo')) {
let value = prop === 'totalSeparation' ? (row[key].separationAmount ? row[key].separationAmount : 0) : row[key].subtotal
if ("/" !== value) {
try {
totalSeparation += parseFloat(value)
} catch (e) {
}
}
}
}
if (totalSeparation !== 0) {
return totalSeparation.toFixed(2);
} else {
return "/"
}
}
const getTotalSummary = (row, prop) => {
let key;
if (prop === 'totalSeparation') {
key = 'separationAmount'
} else {
key = 'subtotal'
}
let result = 0
for (const rowKey of Object.keys(row)) {
if (rowKey.startsWith('personInfo')) {
let value = row[rowKey][key]
if (value && "/" !== value) {
try {
result += parseFloat(value)
} catch (e) {
}
}
}
}
return result.toFixed(2);
}
const concatColumn = (columnIndex, length, rowIndex) => {
if (rowIndex === tableData.value.length - 1) {
return false
}
let columnLength = 5 + (length - 5) * 5
if (columnIndex === 1
|| columnIndex === columnLength - 1) {
return true;
}
for (let i = 0; i < length - 5; i++) {
if (columnIndex === 4 + (i * 5)
|| columnIndex === 5 + (i * 5)
|| columnIndex === 7 + (i * 5)) {
return true
}
}
return false
}
const init = () => {
loading.value = true
getAllocationDetails(route.query.id).then(res => {
columnInfo.value = res.data.columns
let tableDataLet = res.data.tableData;
let personInfoKey = []
columnInfo.value.forEach(item => {
if (item.prop.startsWith('personInfo')) {
personInfoKey.push(item.prop)
}
})
tableData.value = []
let rowIndex = 0;
let summary = {
month: "",
salaryType: '',
projectName: "合计",
totalSeparation: 10,
totalSeparationCost: 10
}
for (const key of personInfoKey) {
summary[key] = {
researchDuration: "",
separationAmount: 0,
subtotal: 0,
wagesPayable: "",
workday: "",
}
}
tableDataLet.forEach((tableDatum) => {
let rowspan = tableDatum.rows.length * 5
monthConcat.set(rowIndex, rowspan)
rowIndex += rowspan
for (const tableDatumElement of tableDatum.rows) {
tableData.value = tableData.value.concat(tableDatumElement)
let row = tableDatumElement[0]
for (const key of personInfoKey) {
try {
if (row[key].subtotal && '/' !== row[key].subtotal) {
summary[key].subtotal += parseFloat(row[key].subtotal)
}
} catch (e) {
}
}
}
})
for (const row of tableData.value) {
for (const key of personInfoKey) {
try {
if (row[key].separationAmount && '/' !== row[key].separationAmount) {
summary[key].separationAmount += parseFloat(row[key].separationAmount)
}
} catch (e) {
}
}
}
for (const key of personInfoKey) {
summary[key].subtotal = summary[key].subtotal.toFixed(2)
summary[key].separationAmount = summary[key].separationAmount.toFixed(2)
}
monthConcat.set(rowIndex, 1)
tableData.value.push(summary)
loading.value = false
})
}
const getResearchOptions = async () => {
const res = await getResearchUser()
researchOptions.value = res.data
}
const getResearchName=(id)=>{
if(!id)return;
let label=''
researchOptions.value.forEach(item=>{
if(item.value==id){
label=item.label
}
})
return label
}
const search = (val) => {
tableConfig.params = {
allocationId:route.query.id,
allocationId: route.query.id,
...val
}
tableIns.value.refresh()
}
getResearchOptions()
</script>
init()
<style scoped>
:deep(.el-table--fit ){
width: 100%;
height: 400px!important;
const exportTable = () => {
const $e = reportTable.value.$el
let $table = $e.querySelector('.el-table__fixed')
if (!$table) {
$table = $e
}
exportExcel($table, (5 + (Object.keys(tableData.value[0]).length - 5) * 5), "四川省国有资产经营投资管理有限责任公司科技创新项目人工成本分摊明细表", 2)
}
</style>
</script>

View File

@@ -134,7 +134,7 @@ const handleReject = async () => {
// ...values
auditOpinion: _value.value
}
console.log('params', params)
// console.log('params', params)
const res = await rejectTask(params)
ElNotification({
title: '提示',

View File

@@ -3,11 +3,13 @@
<el-form :model="localFormData" ref="formRef" label-width="auto" :rules="rules" v-if="step!=='50'">
<el-row>
<el-col :span="12">
<el-form-item label="前置流程" :required="true" prop="requestName">
<a :href="localFormData.preProcess?.baseUrl" target="_blank"
style="color: #2a99ff;margin-right: 10px;cursor: pointer">{{ localFormData.preProcess?.requestName }}</a>
<el-form-item label="前置流程" :required="preProcessRequired" prop="requestName">
<div v-for="item in localFormData.preProcess" :key="item.requestId">
<a :href="item.baseUrl" target="_blank"
style="color: #2a99ff;margin-right: 10px;cursor: pointer">{{ item.requestName }}</a>
</div>
<el-button color="#DED0B2" @click="handleShowPreTable">
{{ localFormData.preProcess?.requestName ? '更改' : '请选择' }}
{{ localFormData.preProcess ? '更改' : '请选择' }}
</el-button>
</el-form-item>
</el-col>
@@ -32,29 +34,12 @@
</div>
</div>
<div class="process">
<operation-render v-if="mode === 'resubmit'&&!changeDiagram" :operation-list="data.operationList" :state="data.state"/>
<operation-render v-if="mode === 'resubmit'&&!changeDiagram" :operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer mode="view" :idName="title" v-if="processDiagramViewer&&changeDiagram"/>
</div>
</div>
</div>
<!-- <div v-if="changeDiagram">-->
<!-- <div class="approval-record">-->
<!-- <div class="approval-title">-->
<!-- <baseTitle title="流程图"></baseTitle>-->
<!-- <div class="diagram">-->
<!--&lt;!&ndash; <div class="base-title">流程图</div>&ndash;&gt;-->
<!--&lt;!&ndash; <el-switch&ndash;&gt;-->
<!--&lt;!&ndash; v-model="changeDiagram"&ndash;&gt;-->
<!--&lt;!&ndash; style="&#45;&#45;el-switch-on-color: #13ce66; &#45;&#45;el-switch-off-color:#BEA266"&ndash;&gt;-->
<!--&lt;!&ndash; />&ndash;&gt;-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="process">-->
<!-- <process-diagram-viewer mode="view" :idName="title" v-if="processDiagramViewer"/>-->
<!-- </div>-->
<!-- </div>-->
<div class="oper-page-btn">
<el-button color="#DED0B2" v-if="mode === 'submit'" @click="handleSubmit">提交</el-button>
<el-button color="#DED0B2" v-else-if="mode === 'resubmit'" @click="handleSubmit">重新提交</el-button>
@@ -71,7 +56,9 @@
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="preProcessList" stripe v-loading="loading">
<el-table :data="preProcessList" stripe v-loading="loading"
@select="handleSelect" row-key="requestId">
<el-table-column type="selection" width="55" :reserve-selection="true"/>
<el-table-column prop="requestId" label="请求id"></el-table-column>
<el-table-column prop="requestName" label="请求名称"></el-table-column>
<el-table-column prop="lastOperatorName" label="最后操作人名称"></el-table-column>
@@ -81,15 +68,17 @@
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<div style="display: flex;align-items: center">
<el-button type="primary" @click="chooseProProcess(scope.row)" link>选择</el-button>
<a :href="scope.row.baseUrl" target="_blank" style="color: #2a99ff;margin-left: 10px">查看流程</a>
</div>
<!-- <el-button type="primary" @click="choosePreProcess(scope.row)" link>选择</el-button>-->
<a :href="scope.row.baseUrl" target="_blank" style="color: #2a99ff;margin-left: 10px">查看流程</a>
</template>
</el-table-column>
</el-table>
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
:total="total" @changeSize="handleSizeChange" @goPage="handleCurrentChange"/>
<div class="oper">
<el-button color="#DED0B2" @click="choosePreProcess">确定</el-button>
<el-button @click="handleCancel">取消</el-button>
</div>
</el-dialog>
</div>
</template>
@@ -147,6 +136,7 @@ const props = defineProps({
const preProcessList = ref([])
//暂存数据
const currentList = ref([])
const preProcessRequired = ref(false)
const total = ref(0)
const preProcessForm = reactive({
requestName: ''
@@ -162,20 +152,40 @@ const tagsViewStore = useTagsView()
const processStore = useProcessStore()
const otherFileList = ref([])
const localFormData = ref({
preProcess: {
requestId: null,
requestName: '',
baseUrl: ''
}
preProcess: [
// {
// requestId: null,
// requestName: '',
// baseUrl: ''
// }
]
})
const attachment = ref()
const deploymentData = ref({})
const showPreTable = ref(false)
const showTable = ref(true)
const loading = ref(false)
const processDiagramViewer = ref(false)
const name = ref(router.currentRoute.value.name)
const deploymentId = ref()
const selectRows = ref([])
const projectId = ref(route.query.projectId)
const getPreProcessUrl = (list) => {
// list.map(item => {
// item.baseUrl = getPreProcessUrl(item.preProcess)
// })
// let baseUrl=
// list.forEach(item => {
// baseUrl=item.baseUrl
// })
// return baseUrl
}
const handleSelect = async (selection) => {
selectRows.value = selection
}
const handleCancel = () => {
showPreTable.value = false
}
const searchPreProcess = () => {
getPreProcessList()
@@ -205,12 +215,19 @@ const getPreProcessList = () => {
preProcessList.value = currentList.value.slice(0, 10)
})
}
const chooseProProcess = (item) => {
localFormData.value.preProcess = {
requestId: item.requestId,
requestName: item.requestName,
baseUrl: item.baseUrl
}
const choosePreProcess = () => {
let preProcessObj = {}
let preProcessArray = []
selectRows.value.forEach((item) => {
preProcessObj = {
requestId: item.requestId,
requestName: item.requestName,
baseUrl: item.baseUrl
}
preProcessArray.push(preProcessObj)
})
localFormData.value.preProcess = preProcessArray
// console.log('localFormData.value.preProcess', localFormData.value.preProcess)
showPreTable.value = false
}
@@ -245,16 +262,16 @@ const compositeParam = (item) => {
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: false,
newFile: true,
tag: getTitleName(props.title)
}
}
const getAttachment = (val) => {
console.log('上传文件getAttachment', val)
// console.log('上传文件getAttachment', val)
localFormData.value.singleFile = compositeParam(val)
}
const getOtherFile = (val) => {
console.log('上传文件getOtherFile', val)
// console.log('上传文件getOtherFile', val)
showTable.value = false
let fileObj = compositeParam(val)
otherFileList.value.push(fileObj)
@@ -269,12 +286,14 @@ const getFileParam = (item) => {
}
}
const handleSubmit = async () => {
if (localFormData.value.preProcess === undefined) {
ElNotification({
title: '提示',
message: '请选择前置流程',
type: 'error'
})
if (deploymentData.value.deploymentName === '重大项目立项' || deploymentData.value.deploymentName === '重大项目验收') {
if (localFormData.value.preProcess === undefined) {
ElNotification({
title: '提示',
message: '请选择前置流程!',
type: 'error'
})
}
}
let files = []
if (props.mode === 'resubmit') {
@@ -289,7 +308,7 @@ const handleSubmit = async () => {
// if (localFormData.value.singleFile !== undefined) {
// localFormData.value.singleFile = getFileParam(localFormData.value.singleFile)
// }
console.log('attachment.value.singleFile', attachment.value, attachment.value.singleFile)
// console.log('attachment.value.singleFile', attachment.value, attachment.value.singleFile)
// if (localFormData.value.singleFile) {
//
// } else {
@@ -314,7 +333,7 @@ const handleSubmit = async () => {
projectId: projectId.value,
preProcess: JSON.stringify(localFormData.value.preProcess)
}
console.log('params', params)
// console.log('params', params)
let res
if (props.step === '20') {
if (props.mode === 'resubmit') {
@@ -372,6 +391,8 @@ const init = async () => {
if (res.code === 1000) {
let data = res.data
deploymentId.value = data.deploymentId
deploymentData.value = data
preProcessRequired.value = data.deploymentName === '重大项目立项' || data.deploymentName === '重大项目验收';
processStore.setDesign(data)
processStore.runningList.value = data.runningList;
processStore.endList.value = data.endList;
@@ -400,5 +421,9 @@ onMounted(async () => {
</script>
<style scoped>
.oper {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
</style>

View File

@@ -96,6 +96,7 @@ import {downloadFile} from "@/api/project-demand";
const changeDiagram = ref(false)
const emit = defineEmits(['getInfo', "update:formData"])
const form = ref()
const router = useRouter()
const props = defineProps({
formData: {
@@ -194,6 +195,16 @@ const fileTable = reactive({
}
]
})
const handleView=(row)=>{
router.push({
name: 'Implementation/detail',
query: {
id: row.requirementId,
projectId: row.projectId,
// step: '40'
}
})
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])

View File

@@ -1,9 +1,9 @@
<template>
<div>
<div style="display: block">
<slot name="pre"></slot>
<div class="user-audit">
<div class="circle-user">
<Tooltip :content="user.name" placement="bottom-start" width="45"/>
<Tooltip :content="user.name" placement="bottom-start" width="45px"/>
<div v-if="user.icon"
class="el-timeline-item__node" :style="{
backgroundColor: user.color
@@ -13,17 +13,12 @@
</el-icon>
</div>
</div>
<div class="username" v-if="user.auditOpinion">
<div style="margin-bottom: 10px;color: #909399">{{user.operationTime}}</div>
<Tooltip :content="user.auditOpinion" placement="bottom-start" width="140" :lines="true"/>
</div>
</div>
</div>
</template>
<script setup>
import {Loading, Close, CircleCheckFilled, MoreFilled} from '@element-plus/icons-vue'
import {defineProps} from "vue";
const props = defineProps({
row: {
@@ -90,15 +85,16 @@ init()
align-items: center;
.circle-user {
width: 50px;
height: 50px;
width: 46px;
height: 46px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
border: 1px solid #ACACAC;
position: relative;
background-color: #8a7243;
color: #fff;
.el-timeline-item__node {
position: absolute;
bottom: 0;
@@ -106,21 +102,6 @@ init()
}
}
.username {
//width: 90px;
margin-top: 10px;
background: #f5f5f5;
padding: 5px;
.el-tooltip__trigger {
width: 90px;
text-align: center;
//padding-top: 2px;
//text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden
}
}
}
</style>

View File

@@ -9,7 +9,8 @@
@cancel="handleCancel"
>
<template #reference>
<el-button v-perm="perm" :type="btnType" size="mini" :disabled="isDisabled" :icon="btnIcon" :plain="isPlain" :link="link">
<!-- v-perm="perm"-->
<el-button :type="btnType" size="mini" :disabled="isDisabled" :icon="btnIcon" :plain="isPlain" :link="link">
{{ btnText }}
</el-button>
</template>
@@ -65,7 +66,6 @@ const handleCancel = () => {
visible.value = false
}
const handleDelete = () => {
console.log('确认')
emit("delete")
}
</script>

View File

@@ -52,7 +52,7 @@ const props = defineProps({
},
uploadState: {
type: Boolean,
default: true
default: false
},
loading: {
type: Boolean,

View File

@@ -5,7 +5,7 @@
placement="bottom-start"
:disabled="isShow"
>
<div :class="lines?'content-lines':'content'" :style="{width: props.width+'px'}" @mouseover="isShowTooltip">
<div :class="lines?'content-lines':'content'" :style="{width: props.width}" @mouseover="isShowTooltip">
<span ref="contentRef">
<slot name="content">{{ props.content }}</slot>
</span>
@@ -17,10 +17,12 @@ const props = defineProps({
content: {
type: String,
default: ''
}, width: {
},
width: {
type: String,
default: ''
}, lines: {
default: '100%'
},
lines: {
type: Boolean,
default: false
}
@@ -40,6 +42,7 @@ const isShowTooltip = () => {
overflow: hidden;
}
.content-lines{
word-break:break-all;
overflow:hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;

View File

@@ -17,6 +17,9 @@
</div>
<!-- 列显示配置 -->
<div v-if="isSettingCol" style="float: right">
<el-button v-if="tableConfig.export && tableConfig.export.open" @click="exportTable" color="#DED0B2"
style="margin-bottom: 10px">导出
</el-button>
<el-tooltip effect="dark" content="列配置" placement="bottom">
<el-button ref="buttonRef" link>
<el-icon size="18">
@@ -101,6 +104,7 @@
<script setup>
import {ElNotification} from 'element-plus';
import {requestList} from '../../api/common';
import {exportExcel} from "@/utils/export-excel";
const props = defineProps({
//表格配置
@@ -129,6 +133,20 @@ const tableInstance = ref()
const buttonRef = ref()
const popoverRef = ref()
const exportTable = () => {
const $e = tableInstance.value.$el
let $table = $e.querySelector('.el-table__fixed')
if (!$table) {
$table = $e
}
let fileName = ""
if (props.tableConfig.export && props.tableConfig.export) {
fileName = props.tableConfig.export.fileName
}
exportExcel($table, Object.keys(localData.list[0]), fileName)
}
const localData = reactive({
list: [], // 表格数据
query: {
@@ -144,7 +162,7 @@ const localData = reactive({
checkGroup: []
})
const emits = defineEmits(['headBtnClick', 'selectionChange', 'rowClick', 'rowDblclick', 'getBaseQuery', 'cellClick'])
const emits = defineEmits(['headBtnClick', 'selectionChange', 'rowClick', 'rowDblclick', 'getBaseQuery', 'cellClick', 'getTotal'])
const handleClickBtns = (key) => {
emits('headBtnClick', key)
@@ -204,13 +222,14 @@ const getList = async () => {
try {
const {code, data, msg} = await requestList(api, queryParmas)
if (code === 1000) {
if(data.rows){
if (data.rows) {
localData.list = data.rows
}else {
} else {
localData.list = data
}
if(data.total){
if (data.total) {
localData.total = data.total
emits('getTotal', localData.total)
}
localData.loading = false
} else {

View File

@@ -6,13 +6,52 @@
<!-- <bell-socket/>-->
<div class="user-box">
<div>
<!-- <img :src="userInfo.avatar" alt="" @click.stop="handleVisitedP">-->
<span @click.stop="handleVisitedP">欢迎回来{{ userInfo.userName }}</span>
<el-avatar>{{ userInfo.nickName }}</el-avatar>
<div @click.stop="handleVisitedP">{{ userInfo.nickName }}
<el-icon style="margin-left: 5px">
<ArrowDownBold/>
</el-icon>
</div>
</div>
<div class="person" v-if="visitedP">
<ul>
<li @click="handleToAuth">个人中心</li>
<li @click="handleLogout">退出登录</li>
<li>主次账号切换</li>
<li class="avatar-li" v-for="item in accountList" @click="accountChange(item.userId)">
<el-badge :value="item.taskCount" v-if="item.taskCount!==0">
<el-avatar>{{ item.nickName }}</el-avatar>
</el-badge>
<el-avatar v-else>{{ item.nickName }}</el-avatar>
<div class="right-li">
<div class="name-line">
<span v-if="item.accountType==='0'" class="zhu"></span>
<span class="nickName">{{ item.nickName }}</span>
<span :title="item.jobActivityDesc">{{ item.jobActivityDesc }}</span>
</div>
<div>
<span :title="item.companyName+'/'+item.departmentName">{{ item.companyName }}/{{
item.departmentName
}}</span>
</div>
</div>
<div>
<el-icon color="#3f89dc" size="20" v-if="item.current">
<SuccessFilled/>
</el-icon>
</div>
<!-- <li v-for="item in accountList" :label="item.userName" :value="item.userId"/>-->
</li>
<!-- <li @click="handleToAuth">-->
<!-- <el-icon color="gray" size="20" style="margin-right: 5px">-->
<!-- <UserFilled/>-->
<!-- </el-icon>-->
<!-- 个人中心-->
<!-- </li>-->
<li @click="handleLogout">
<el-icon color="gray" size="20" style="margin-right: 5px">
<SwitchButton/>
</el-icon>
退出登录
</li>
</ul>
</div>
</div>
@@ -26,13 +65,18 @@ import Breadcrumb from './Breadcrumb.vue';
import Hamburger from './Hamburger.vue';
import {useAuthStore} from '@/stores/userstore.js'
import {usePermisstionStroe} from '@/stores/permisstion'
import { useTagsView } from '@/stores/tagsview';
import {useTagsView} from '@/stores/tagsview';
import {getUserAccount} from "@/api/user/user";
import {switchAccount} from "@/api/login";
import {setToken} from "../../utils/auth";
import {ElNotification} from "element-plus";
const authStore = useAuthStore()
const permisstionStore = usePermisstionStroe()
const tagsViewStore = useTagsView()
const userInfo = ref({})
const visitedP = ref(false)
const accountList = ref([])
const router = useRouter()
onMounted(() => {
setUserInfo()
@@ -48,7 +92,32 @@ const nullBlockClick = () => {
visitedP.value = false
}
const handleVisitedP = () => {
visitedP.value = !visitedP.value
getUserAccount().then(res => {
if (res.code !== 1000) {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
accountList.value = res.data
nextTick(() => {
visitedP.value = !visitedP.value
})
})
}
const accountChange = (userId) => {
switchAccount(userId).then(res => {
if (res.code == 1000) {
visitedP.value = !visitedP.value
authStore.userLogout()
setToken(res.data)
router.push('/')
location.reload()
visitedP.value = false
}
})
}
const handleToAuth = () => {
@@ -63,9 +132,30 @@ const handleLogout = () => {
tagsViewStore.removeAllTagView()
router.push('/login')
}
</script>
<style lang="scss" scoped>
:deep(.el-avatar--circle) {
display: inline-block;
line-height: 40px;
margin-right: 14px;
background-color: #8a7243;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
:deep(.el-badge) {
padding: 0 2px;
}
:deep(.el-badge__content.is-fixed) {
position: absolute;
right: 26px;
top: 2px;
}
.navbar {
height: 65px;
padding: 0 15px 0 0;
@@ -90,8 +180,9 @@ const handleLogout = () => {
display: flex;
align-items: center;
> span {
margin-left: 5px;
> div {
display: flex;
align-items: center;
}
img {
@@ -105,24 +196,85 @@ const handleLogout = () => {
.person {
font-size: 14px;
color: #666666;
position: absolute;
width: 80px;
width: 280px;
right: 0;
z-index: 300;
bottom: -70px;
padding: 10px 5px;
top: 54px;
padding: 5px 0;
border-radius: 4px;
background-color: #fff;
box-shadow: 2px 2px 2px 1px rgb(171, 167, 167);
.avatar-li {
display: flex;
height: 60px;
.right-li {
color: #909090;
display: flex;
flex-direction: column;
.name-line {
margin-bottom: 5px;
width: 184px;
-webkit-line-clamp: 1;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
.zhu {
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
background-color: #fa0;
color: #fff;
text-align: center;
}
.nickName {
color: #4d7ad8;
}
> span {
margin-right: 5px;
}
}
> div:last-child {
width: 194px;
-webkit-line-clamp: 1;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
}
li {
text-align: center;
padding: 0 6px;
height: 28px;
display: flex;
align-items: center;
text-align: left;
font-size: 14px;
line-height: 1.5;
cursor: pointer;
border-bottom: 1px solid #e6e6e6;
&:hover {
color: #79bbff;
color: #666666 !important;
background-color: #eaeaea;
}
&:first-child:hover {
background-color: #fff;
}
&:last-child {
border-bottom: none;
}
}
}

View File

@@ -25,6 +25,11 @@ const router = createRouter({
name: 'casLogin',
component: () => import('@/views/cas-login/index.vue'),
},
{
path: '/projectdetail/mobile',
name: 'projectDetailMobile',
component: () => import('@/views/project-management/mobledetail/index.vue')
},
{
path: '/',
name: 'layout',

View File

@@ -39,8 +39,8 @@ export const useProcessStore = defineStore('process', () => {
}
const delProcess = (delNode) => {
processData.value.process.splice(processData.value.process.indexOf(delNode), 1)
console.log("删除数据")
console.log(processData.value.process)
// console.log("删除数据")
// console.log(processData.value.process)
}
const getDesign = () => {

View File

@@ -53,7 +53,7 @@ export const useTagsView = defineStore('tagsView',()=>{
//路由到末尾标签页
const toLastTagView = (view) => {
const lastTagView = view.value.slice(-1)[0]
router.push(lastTagView.path)
router.push({path: lastTagView.path, query: lastTagView.query})
}
const removeAllTagView = () => {

View File

@@ -1,8 +1,9 @@
export const toThousands = (num) => {
if(num==undefined||num==null)return '--';
const options = {
style: 'currency',
currency: 'CNY',
};
return (num).toLocaleString('zh-CN', options)
let newNum=Number(num)
if (newNum == undefined || newNum == null) return '--';
const options = {
style: 'currency',
currency: 'CNY',
};
return (newNum).toLocaleString('zh-CN', options)
}

117
src/utils/export-excel.js Normal file
View File

@@ -0,0 +1,117 @@
import {utils} from "xlsx";
import FileSaver from 'file-saver'
import XLSX from "xlsx-style-vite";
/**
* 导出excel
* @param $table 表格html dom元素
* @param columnLength 列长度
* @param excelName 导出文件名称
* @param bigWidthIndex 更宽列的索引
*/
export function exportExcel($table, columnLength, excelName, bigWidthIndex) {
//从el-table表生成工作簿对象
//使用原始的格式,保留表格中的格式如%、小数末尾的0等
let workbook = utils.table_to_book($table, {
raw: true
});
//列宽需要导出的表格有多少列这里的i就小于多少
for (let i = 1; i < columnLength; i++) {
if (i === bigWidthIndex) {
workbook.Sheets.Sheet1["!cols"].push({wpx: 300});
}
workbook.Sheets.Sheet1["!cols"].push({wpx: 100});
}
//设置单元格样式
for (const key in workbook.Sheets.Sheet1) {
if (
key !== "!cols" &&
key !== "!fullref" &&
key !== "!merges" &&
key !== "!ref" &&
key !== "!rows"
) {
//这里的s就是具体的样式如果想设置不一样的样式可以看xlsx-style文档
workbook.Sheets.Sheet1[key].s = {
//边框
border: {
top: {style: "thin"},
bottom: {style: "thin"},
left: {style: "thin",},
right: {style: "thin",}
},
//对齐
alignment: {
horizontal: "center",
vertical: "center",
wrapText: true
}
};
}
}
//修改合并单元格样式
let arr = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
//由于导出时合并单元格只识别左上角的单元格,合并单元格中其他单元格
//并不会存在,所以需要识别合并单元格中除左上角单元格外的单元格并添加
//带样式的单元格到其中不理解可以看四中的第2点。
try {
for (let item of workbook.Sheets.Sheet1["!merges"]) {
let style = {
border: {
top: {style: "thin"},
bottom: {style: "thin"},
left: {style: "thin",},
right: {style: "thin",}
},
alignment: {
horizontal: "center",
vertical: "center",
wrapText: true
}
};
let merge_s = {t: "s", v: "", s: style};
if (item.s.c === item.e.c) {
//纵向合并其中c为字母r为数字
let star = item.s.r;
let end = item.e.r;
for (let i = star + 1; i <= end; i++) {
workbook.Sheets.Sheet1[arr[item.s.c] + (i + 1)] = merge_s;
}
} else {
//横向合并
let star = item.s.c;
let end = item.e.c;
for (let i = star; i < end; i++) {
workbook.Sheets.Sheet1[arr[i + 1] + Number(item.s.r + 1)] = merge_s;
}
}
}
} catch (e) {
}
//将表格数据中的字符串转ArrayBuffer
function s2ab(s) {
let buf = new ArrayBuffer(s.length);
let view = new Uint8Array(buf);
for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
return buf;
}
//这里的属性可以参考xlsx-style文档
let wbout = XLSX.write(workbook, {
bookType: "xlsx",
bookSST: false,
type: "binary"
});
try {
FileSaver.saveAs(
new Blob([s2ab(wbout)], {type: "application/octet-stream"}),
`${excelName}.xlsx`
);
} catch (e) {
if (typeof console !== "undefined") console.log(e, wbout);
}
}

View File

@@ -317,7 +317,7 @@ const handleEdit = async (id) => {
restFrom()
getDataSourceManageDetails(id).then(res => {
if (res.code === 1000) {
console.log('res', res.data)
// console.log('res', res.data)
formRules.value.password[0].required = false
form.value = res.data
title.value = "编辑数据模型管理"

View File

@@ -256,7 +256,7 @@ const changeChartItem = (event) => {
}
arr.push(obj)
})
console.log('arr',arr)
// console.log('arr',arr)
for (const propertyName in option.legend.selected) {
if (propertyName === item.label) {
option.legend.selected[propertyName] = true
@@ -296,10 +296,10 @@ const startDrag = (event) => {
flag.value = false
}
} else if (chart === 'pie') {
console.log('拖动饼图')
// console.log('拖动饼图')
flag.value = false
}else if (chart === 'radar') {
console.log('拖动雷达')
// console.log('拖动雷达')
flag.value = false
}
}

View File

@@ -273,7 +273,7 @@ const isShowAxisLine = (type) => {
* 初始化echarts实例方法
*/
const initChart = () => {
console.log('initChartoption', option)
// console.log('initChartoption', option)
//3.初始化container容器
myEcharts = echarts.init(chart.value);
//5.传入数据
@@ -293,7 +293,7 @@ const initChart = () => {
* 保存数据
*/
const saveData = () => {
console.log('最终initInfo', initInfo)
// console.log('最终initInfo', initInfo)
emit("getFinalInfo", initInfo)
}
/**

View File

@@ -34,9 +34,10 @@ const searchConfig = reactive([
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
colProps: {}
}, {
},
{
label: '项目费用',
prop: 'requirementName',
prop: 'projectCost',
component: shallowRef(fvSelect),
props: {
placeholder: '请选择项目费用查询',
@@ -44,16 +45,17 @@ const searchConfig = reactive([
filterable: true,
cacheKey: 'project_cost',
}
}, {
label: '项目阶段',
},
{
label: '研发阶段',
prop: 'researchStage',
component: shallowRef(fvSelect),
props: {
placeholder: '请选择项目阶段查询',
placeholder: '请选择研发阶段查询',
clearable: true,
filterable: true,
checkStrictly: true,
cacheKey: 'research_stage',
cacheKey: 'fee_stage',
}
},
{
@@ -113,7 +115,7 @@ const tableConfig = reactive({
},
{
prop: 'researchStage',
label: '项目阶段',
label: '研发阶段',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
@@ -124,6 +126,11 @@ const tableConfig = reactive({
}
}
},
{
label: '摘要',
prop: 'digest',
align: 'center'
},
{
prop: 'afterTax',
label: '税后余额(元)',

View File

@@ -38,80 +38,63 @@
</el-table-column>
<el-table-column prop="researchPersonnel" label="研发人员" width="230">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.researchPersonnel?'1':rules.researchPersonnel">
<el-select v-model="scope.row.researchPersonnel" placeholder="请选择研发人员" clearable>
<el-option
v-for="item in researchOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<el-form-item prop="researchPersonnel">
{{ scope.row.researchPersonnelName ? scope.row.researchPersonnelName : currentReachPerson.name }}
<el-button @click="showPersonnelPicker(scope.row,scope.$index)">
{{ scope.row.researchPersonnelName || currentReachPerson.name ? '更改' : '请选择研发人员' }}
</el-button>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="wagesPayable" label="应发工资">
<el-table-column prop="wagesPayable" label="应发工资" width="175">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.wagesPayable?'1':rules.wagesPayable">
<el-input-number v-model="scope.row.wagesPayable" placeholder="请输入应发工资" :controls="false"/>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="performance" label="绩效">
<el-table-column prop="performance" label="绩效" width="175">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.performance?'1':rules.performance">
<el-form-item prop="time">
<el-input-number v-model="scope.row.performance" placeholder="请输入绩效" :controls="false"/>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="reserveFund" label="公积金">
<el-table-column prop="reserveFund" label="公积金" width="175">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.reserveFund?'1':rules.reserveFund">
<el-input-number v-model="scope.row.reserveFund" placeholder="请输入公积金" :controls="false"/>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="socialSecurity" label="社保">
<el-table-column prop="socialSecurity" label="社保" width="175">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.socialSecurity?'1':rules.socialSecurity">
<el-input-number v-model="scope.row.socialSecurity" placeholder="请输入社保" :controls="false"/>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="annuity" label="年金">
<el-table-column prop="annuity" label="年金" width="175">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.annuity?'1':rules.annuity">
<el-input-number v-model="scope.row.annuity" placeholder="请输入年金" :controls="false"/>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="workday" label="工作日(天)">
<el-table-column prop="workday" label="工作日(天)" width="175">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.workday?'1':rules.workday">
<el-input-number v-model="scope.row.workday" placeholder="请输入工作日" :controls="false"/>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="researchDuration" label="研发时长(天)" >
<el-table-column prop="researchDuration" label="研发时长(天)" width="175">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.researchDuration?'1':rules.researchDuration">
<el-input-number v-model="scope.row.researchDuration" placeholder="请输入研发时长" :controls="false"/>
</el-form-item>
</template>
</el-table-column>
<!-- <el-table-column prop="time" label="时间">-->
<!-- <template #default="scope">-->
<!-- <el-input v-model="scope.row.time" placeholder="请输入时间" clearable>-->
<!-- </el-input>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column prop="subtotal" label="小计">-->
<!-- <template #default="scope">-->
<!-- <el-input v-model="scope.row.subtotal" placeholder="请输入小计" clearable>-->
<!-- </el-input>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column prop="oper" label="操作">
<template #default="scope">
<el-button type="primary" @click="handleCopy(scope.row)" link style="font-size: 18px">复制</el-button>
@@ -121,18 +104,31 @@
</el-table>
</el-row>
</el-form>
<user-picker :multiple="false" ref="userPicker" title="请选择研发人员" v-model:value="userList" @ok="selected"
:setNullToSelectList="true"/>
<div style="width:100%;text-align: center;padding: 10px">
<el-button type="primary" @click="handleAdd" link style="font-size: 18px">添加一行</el-button>
</div>
<div class="approval-record">
<div style="display: flex;align-items: center;margin-bottom: 20px">
<baseTitle title="流程图"></baseTitle>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color: #13ce66; --el-switch-off-color:#BEA266;margin-left: 10px"
/>
<div class="approval-title">
<baseTitle title="审批记录" v-if="processDiagramViewer&& opentionData?.operationList"></baseTitle>
<div v-else></div>
<div style="display: flex;align-items: center;justify-content: flex-end;">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color: #13ce66; --el-switch-off-color:#BEA266;margin-left: 10px"
/>
</div>
</div>
<div class="process">
<operation-render
v-if="processDiagramViewer&& opentionData?.operationList && opentionData?.operationList.length > 0&&!changeDiagram"
:operation-list="opentionData?.operationList"
:state="opentionData.state"/>
<process-diagram-viewer mode="view" v-if="processDiagramViewer&&changeDiagram"/>
</div>
<process-diagram-viewer mode="view" v-if="processDiagramViewer&&changeDiagram"/>
</div>
<div class="oper-page-btn">
<el-button color="#DED0B2" v-if="routerName==='Share/add'" @click="handleSubmit(form)">提交</el-button>
@@ -145,16 +141,29 @@
<script setup lang="jsx">
import {ElNotification} from "element-plus";
import {useTagsView} from '@/stores/tagsview.js'
import {addAllocation, getAllocationDetail, getAllocationProcess, getResearchUser,getProjectOption,editAllocation, getAllocationDetailList} from "@/api/expense-manage";
import {
addAllocation,
getAllocationDetail,
getAllocationProcess,
getResearchUser,
getProjectOption,
editAllocation,
getAllocationDetailList
} from "@/api/expense-manage";
import {useProcessStore} from '@/stores/processStore.js';
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import {ref} from "vue";
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
const userList = ref([])
const changeDiagram = ref(false)
const rules = reactive({
shareName: [{required: true, message: '请输入分摊名称', trigger: 'blur'}],
apportionmentMonth: [{required: true, message: '请选择月份', trigger: 'blur'}],
projectId: [{required: true, message: '请选择项目名称', trigger: 'blur'}],
researchPersonnel: [{required: true, message: '请选择研发人员', trigger: 'blur'}],
// researchPersonnel: [{required: true, message: '请选择研发人员', trigger: 'blur'}],
wagesPayable: [{required: true, message: '请输入应发工资', trigger: 'blur'}],
performance: [{required: true, message: '请输入绩效', trigger: 'blur'}],
reserveFund: [{required: true, message: '请输入公积金', trigger: 'blur'}],
@@ -164,6 +173,7 @@ const rules = reactive({
researchDuration: [{required: true, message: '请输入研发时长', trigger: 'blur'}],
})
const processStore = useProcessStore()
const opentionData = ref()
const processInstanceData = ref()
const processDiagramViewer = ref(false)
const loading = ref(false)
@@ -175,23 +185,42 @@ const tagsViewStore = useTagsView()
const formData = ref({
tableData: [
{
projectId:'',
projectId: '',
projectName: '',
researchPersonnel:'',
wagesPayable:null,
performance:null,
reserveFund:null,
socialSecurity:null,
annuity:null,
workday:'21.75',
researchDuration:null,
researchPersonnel: '',
wagesPayable: null,
performance: null,
reserveFund: null,
socialSecurity: null,
annuity: null,
workday: '21.75',
researchDuration: null,
}
]
})
const userPicker = ref()
const form = ref()
const currentReachPerson = ref({})
const currentRow = ref()
const currentIndex = ref()
const nameOptions = ref([])
const researchOptions = ref([])
const showPersonnelPicker = (row, index) => {
currentRow.value = row
currentIndex.value = index
userPicker.value.showUserPicker()
}
const selected = (select) => {
for (const selectElement of select) {
currentReachPerson.value = selectElement
}
formData.value.tableData.forEach((item, index) => {
if (index == currentIndex.value) {
item.researchPersonnel = currentReachPerson.value.id
item.researchPersonnelName = currentReachPerson.value.name
}
})
}
const getResearchOptions = async () => {
const res = await getResearchUser()
researchOptions.value = res.data
@@ -200,11 +229,11 @@ const getProjectOptions = async () => {
const res = await getProjectOption()
nameOptions.value = res.data
}
const getProjectName=(id)=>{
let label=''
nameOptions.value.forEach(item=>{
if(item.value===id){
label=item.label
const getProjectName = (id) => {
let label = ''
nameOptions.value.forEach(item => {
if (item.value === id) {
label = item.label
}
})
return label
@@ -214,13 +243,13 @@ const handleAdd = () => {
projectId: '',
projectName: '',
researchPersonnel: '',
wagesPayable:null,
performance:null,
reserveFund:null,
socialSecurity:null,
annuity:null,
workday:'21.75',
researchDuration:null,
wagesPayable: null,
performance: null,
reserveFund: null,
socialSecurity: null,
annuity: null,
workday: '21.75',
researchDuration: null,
}
formData.value.tableData.push(row)
}
@@ -228,13 +257,13 @@ const handleCopy = (row) => {
let copyObj = {
projectId: row.projectId,
projectName: '',
researchPersonnel: row.researchPersonnel,
researchPersonnel: row.researchPersonnel,
wagesPayable: row.wagesPayable,
performance: row.performance,
reserveFund: row.reserveFund,
socialSecurity: row.socialSecurity,
annuity: row.annuity,
workday:'21.75',
workday: '21.75',
researchDuration: row.researchDuration,
}
formData.value.tableData.push(copyObj)
@@ -245,7 +274,7 @@ const handleDelete = (index) => {
const handleSubmit = (instance) => {
if (!instance) return
instance.validate(async (valid) => {
if (!valid){
if (!valid) {
return ElNotification({
title: '提示',
message: '请完善数据,再提交!',
@@ -254,14 +283,17 @@ const handleSubmit = (instance) => {
}
formData.value.tableData.forEach(item => {
item.projectName = getProjectName(item.projectId)
if (item.performance == 0) {
item.performance = null
}
})
let params = {
shareName:formData.value.shareName,
apportionmentMonth:formData.value.apportionmentMonth,
shareName: formData.value.shareName,
apportionmentMonth: formData.value.apportionmentMonth,
usrAllocations: formData.value.tableData,
deploymentId: processInstanceData.value.deploymentId,
}
// console.log('params',params)
console.log('params', params, formData.value.tableData)
const {code, msg} = await addAllocation(params)
ElNotification({
title: '提示',
@@ -279,7 +311,7 @@ const handleSubmit = (instance) => {
const handleResubmit = (instance) => {
if (!instance) return
instance.validate(async (valid) => {
if (!valid){
if (!valid) {
return ElNotification({
title: '提示',
message: '请完善数据,再提交!',
@@ -289,15 +321,18 @@ const handleResubmit = (instance) => {
formData.value.tableData.forEach(item => {
item.allocationId = formData.value.allocationId
item.projectName = getProjectName(item.projectId)
if (item.performance == 0) {
item.performance = null
}
})
let params = {
allocationId:formData.value.allocationId,
shareName:formData.value.shareName,
apportionmentMonth:formData.value.apportionmentMonth,
allocationId: formData.value.allocationId,
shareName: formData.value.shareName,
apportionmentMonth: formData.value.apportionmentMonth,
usrAllocations: formData.value.tableData,
deploymentId: processInstanceData.value.deploymentId,
}
// console.log('params',params)
console.log('params', params)
const {code, msg} = await editAllocation(params)
ElNotification({
title: '提示',
@@ -313,8 +348,8 @@ const handleResubmit = (instance) => {
})
}
const getDetailInfo = async () => {
loading.value=true
const getDetailInfo = () => {
loading.value = true
getAllocationDetail(route.query.id).then(res => {
ElNotification({
title: '提示',
@@ -322,8 +357,9 @@ const getDetailInfo = async () => {
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
getDetailList()
getDetailList()
formData.value = res.data.formData
opentionData.value = res.data
loading.value = false
}
})
@@ -332,7 +368,7 @@ const getDetailList = async () => {
let params = {
allocationId: route.query.id
}
showTable.value=false
showTable.value = false
const {code, data, msg} = await getAllocationDetailList(params)
if (code === 1000) {
data.rows.forEach(item => {
@@ -342,11 +378,11 @@ const getDetailList = async () => {
nextTick(() => {
showTable.value = true
})
}else {
} else {
ElNotification({
title: '提示',
message: msg,
type: 'error'
type: 'error'
})
}
}
@@ -379,10 +415,21 @@ const init = async () => {
const handleBack = () => {
history.back()
}
onMounted(async () => {
await init()
onMounted(() => {
init()
if (route.query.id) {
await getDetailInfo()
getDetailInfo()
}
})
</script>
<style scoped lang="scss">
:deep(.el-table--enable-row-transition) {
.el-table__body td.el-table__cell {
.cell {
.el-form-item {
margin-top: 20px;
}
}
}
}
</style>

View File

@@ -18,24 +18,20 @@
<expense-detail/>
</el-tab-pane>
<el-tab-pane label="分摊汇总" name="second" v-loading="loading">
<fvTable v-if="showTable" ref="tableRef" :tableConfig="tableConfig">
<template #empty>
<el-empty description="暂无数据"/>
</template>
</fvTable>
<allocation-summary-detail/>
</el-tab-pane>
</el-tabs>
<div v-if="shareData.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="auditOpinion">
<el-input
v-model="auditOpinion"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
<div v-if="shareData.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="auditOpinion">
<el-input
v-model="auditOpinion"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
<div class="approval-record">
<div class="approval-title">
<baseTitle title="审批记录"></baseTitle>
@@ -48,16 +44,18 @@
</div>
</div>
<div class="process">
<operation-render v-if="shareProcessViewer&& shareData.operationList && shareData.operationList.length > 0&&!changeDiagram" :operation-list="shareData.operationList"
:state="shareData.state"/>
<operation-render
v-if="shareProcessViewer&& shareData.operationList && shareData.operationList.length > 0&&!changeDiagram"
:operation-list="shareData.operationList"
:state="shareData.state"/>
<process-diagram-viewer v-if="shareProcessViewer&&changeDiagram" id-name="shareProcess"/>
</div>
</div>
<opinion v-if="shareData.taskId" :formData="shareData.formData" :taskId="shareData.taskId" v-model:value="auditOpinion"></opinion>
<opinion v-if="shareData.taskId" :formData="shareData.formData" :taskId="shareData.taskId"
v-model:value="auditOpinion"></opinion>
</template>
<script setup lang="jsx">
import {toThousands} from '@/utils/changePrice.js'
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {ElNotification} from "element-plus";
@@ -71,61 +69,9 @@ const shareData = ref({})
const formData = ref({})
const auditOpinion = ref('')
const shareProcessViewer = ref(true)
const showTable = ref(true)
const loading = ref(false)
const activeName = ref('first')
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'projectName',
label: '项目名称',
align: 'center',
},
{
prop: 'projectCost',
label: '费用性质',
align: 'center',
currentRender: ({row, index}) => {
if (row.projectCost !== null) {
return (<Tag dictType={'project_cost'} value={row.projectCost}/>)
} else {
return '--'
}
}
},
{
prop: 'researchStage',
label: '项目阶段',
align: 'center',
currentRender: ({row, index}) => {
if (row.researchStage&&row.researchStage !== null&&row.researchStage!==undefined) {
return (<Tag dictType={'research_stage'} value={row.researchStage}/>)
} else {
return '--'
}
}
},
{
prop: 'afterTax',
label: '分摊金额',
align: 'center',
currentRender:({row})=>{
return <span>{toThousands(row.afterTax)}</span>
}
}
],
api:'/workflow/mosr/cost/allocation/collect',
params:{
allocationId:route.query.id
}
})
// const activeName = ref('second')
const getDetail = async () => {
const id = route.query.id
@@ -140,7 +86,7 @@ const getDetail = async () => {
processStore.noTakeList.value = data.noTakeList;
processStore.refuseList.value = data.refuseList;
processStore.passList.value = data.passList;
nextTick(()=>{
nextTick(() => {
shareProcessViewer.value = true
})
} else {
@@ -152,18 +98,20 @@ const getDetail = async () => {
}
}
const handleClick = (tab) => {
if (tab.index==0) {
if (tab.index == 0) {
getDetail()
}
}
getDetail()
</script>
<style scoped lang="scss">
:deep(.el-table--fit ){
:deep(.el-table--fit ) {
width: 100%;
height: 400px!important;
height: 479px !important;
}
:deep(.el-tabs__nav-scroll) {
width: 100%;
display: flex;

View File

@@ -13,6 +13,35 @@ import { ElNotification} from "element-plus";
import {deleteAllocation} from "@/api/expense-manage";
const router = useRouter();
const shortcuts = [
{
text: '上周',
value: () => {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
return [start, end]
},
},
{
text: '上月',
value: () => {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
return [start, end]
},
},
{
text: '三月前',
value: () => {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
return [start, end]
},
},
]
const searchConfig = reactive([
{
label: '分摊名称',
@@ -24,7 +53,8 @@ const searchConfig = reactive([
filterable: true,
checkStrictly: true
}
}, {
},
{
label: '分摊月份',
prop: 'apportionmentMonth',
component: 'el-date-picker',
@@ -32,18 +62,23 @@ const searchConfig = reactive([
placeholder: '请选择分摊月份',
clearable: true,
type:'month',
valueFormat:"YYYY-MM-DD HH:mm:ss"
format: 'YYYY-MM',
valueFormat:"YYYY-MM"
},
colProps: {}
},
{
label: '生成时间',
prop: 'generationTime',
prop: 'dateValue',
component: 'el-date-picker',
props: {
placeholder: '请选择生成时间',
clearable: true,
type: 'daterange',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
shortcuts: shortcuts
},
colProps: {}
},
@@ -147,7 +182,13 @@ const tableConfig = reactive({
})
const search = (val) => {
tableConfig.params = {...val}
let obj = {...val}
if (obj.dateValue) {
obj.startGenerationTime = obj.dateValue[0]
obj.endGenerationTime = obj.dateValue[1]
delete obj.dateValue
}
tableConfig.params = obj
tableIns.value.refresh()
}
const handleAdd = () => {

View File

@@ -16,7 +16,7 @@
</el-col>
</el-row>
<h4>待办 ({{ todoNum }})</h4>
<fvTable ref="tableIns" class="home-table" :tableConfig="tableConfig">
<fvTable ref="tableIns" class="home-table" :tableConfig="tableConfig" @getTotal="getTotal">
<template #empty>
<el-empty description="暂无待办"/>
</template>
@@ -101,7 +101,7 @@ const helpDocList = ref([
title: '业务流程'
}
])
const todoNum = ref(20)
const todoNum = ref(0)
const tableConfig = reactive({
columns: [
{
@@ -156,6 +156,9 @@ const tableConfig = reactive({
api: '/workflow/mosr/process/task',
params: {},
})
const getTotal=(val)=>{
todoNum.value=val
}
const handleView = (row) => {
if (row.targetState == '00' && row.targetId) {
router.push({

View File

@@ -12,7 +12,7 @@
<el-form-item label="征集类型" prop="collectType">
<el-select v-model="formData.collectType" placeholder="征集类型" clearable filterable>
<el-option
v-for="item in typeOption"
v-for="item in cacheStore.getDict('collect_type')"
:key="item.value"
:label="item.label"
:value="item.value"
@@ -34,10 +34,13 @@
</el-col>
<el-col :span="24">
<el-form-item label="所属公司" prop="companyIds" class="tree-select">
<div>{{ getName(companyList) }}</div>
<el-button color="#DED0B2" @click="showCompany">{{companyList.length===0?'请选择所属公司':'更改'}}</el-button>
<!-- <el-tree-select v-model="formData.companyIds" :data="companyOption"-->
<!-- filterable clearable :check-strictly="true" multiple/>-->
<div v-if="route.query.id" :class="showExpendClass(showMoreCompany)">{{ selectedCompanyList }}</div>
<div v-else :class="showExpendClass(showMoreCompany)">{{ getName(selectedCompanyList) }}</div>
<div style="color: #2a99ff;text-align: center;width: 100%;font-size: 15px;cursor: pointer"
@click="handleExpend">{{ showExpendText }}
</div>
<el-button color="#DED0B2" @click="showCompany">{{ selectedCompanyList.length === 0 ? '请选择所属公司' : '更改' }}
</el-button>
</el-form-item>
</el-col>
<el-col :span="6">
@@ -80,8 +83,8 @@
</template>
</fvTable>
<div class="approval-record">
<div style="display: flex;align-items: center;margin-bottom: 20px">
<baseTitle title="流程图"></baseTitle>
<div style="display: flex;align-items: center;justify-content: flex-end;">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color: #13ce66; --el-switch-off-color:#BEA266;margin-left: 10px"
@@ -89,12 +92,13 @@
</div>
<process-diagram-viewer mode="view" v-if="processDiagramViewer&&changeDiagram"/>
</div>
<div style="width: 100%;height: 30px"></div>
<div class="oper-page-btn">
<el-button color="#DED0B2" v-if="routerName==='Requirement/add'" @click="handleSubmit(demandForm)">提交</el-button>
<el-button color="#DED0B2" v-else @click="handleResubmit">重新提交</el-button>
<el-button @click="handleBack">返回</el-button>
</div>
<company-picker :multiple="true" ref="companyRef" title="请选择所属公司" v-model:value="companyList" @ok="selected"/>
<company-picker :multiple="true" ref="companyRef" title="请选择所属公司" @ok="selected"/>
</div>
</template>
@@ -117,9 +121,16 @@ import {getSubCompOpt} from '@/api/user/user.js'
import {useTagsView} from '@/stores/tagsview.js'
import {getFundOption} from "@/api/special-fund";
import CompanyPicker from "@/components/DetailComponent/CompanyPicker.vue";
import {matterTree} from "@/utils/matterTree";
import {useCacheStore} from '@/stores/cache.js'
const cacheStore = useCacheStore()
const companyRef = ref()
const companyList = ref([])
const showExpendText = ref('')
const showMoreCompany = ref(false)
const selectedCompanyList = ref([])
// const companyList = ref([])
const changeDiagram = ref(false)
const tagsViewStore = useTagsView()
const authStore = useAuthStore()
@@ -139,23 +150,19 @@ const formData = ref({
const showTinymce = ref(true)
const routerName = ref(router.currentRoute.value.name)
const processDiagramViewer = ref(false)
const typeOption = ref([
{
label: "需求征集",
value: '需求征集'
}
])
const companyOption = ref([])
const specialFundOption = ref([])
const form = ref(null)
const expendClass = ref()
const fileList = ref([])
const loading = ref(false)
const showTable = ref(true)
const processStore = useProcessStore()
const processInstanceData = ref()
const formPermMap = ref(new Map());
const companyNameArray = ref([])
const rules = reactive({
requirementName: [{required: true, message: '请输入需求名称', trigger: 'blur'}],
requirementName: [{required: true, message: '请输入征集名称', trigger: 'blur'}],
companyIds: [{required: true, message: '请选择所属公司', trigger: 'blur'}],
collectType: [{required: true, message: '请选择征集类型', trigger: 'blur'}],
deadline: [{required: true, message: '请选择截止时间', trigger: 'blur'}],
@@ -205,23 +212,44 @@ const tableConfig = reactive({
}
]
})
const handleExpend = () => {
showMoreCompany.value = !showMoreCompany.value;
showExpendClass(showMoreCompany.value)
}
const showExpendClass = (showMoreCompany) => {
if (!showMoreCompany) {
if (selectedCompanyList.value.length === 0) {
showExpendText.value = ''
return ''
} else if (selectedCompanyList.value.length>14) {
showExpendText.value = '展开'
return 'company-style'
}
} else {
showExpendText.value = '收缩'
return ''
}
}
const getCompanyOptionItem = (val) => {
if (val !== undefined) {
val.forEach(item => {
matterTree(companyNameArray.value, companyOption.value, item)
})
}
return companyNameArray.value.join('');
}
const getName = (list) => {
return list.map(item => item.label).join('')
}
const showCompany = () => {
companyRef.value.show()
}
const selected = (select) => {
let companyInfoList = []
for (let val of select) {
let companyInfo = {
value: val.value,
label: val.label
}
companyInfoList.push(companyInfo)
formData.value.companyIds.push(val.value)
}
companyList.value = companyInfoList
selectedCompanyList.value = select
}
const checkFormPrem = (formKey) => {
if (formPermMap.value.hasOwnProperty(formKey)) {
@@ -312,8 +340,7 @@ const init = async () => {
})
}
const submitParam = (item) => {
console.log('item..',item.companyIds)
if(item.companyIds.length===0){
if (item.companyIds.length === 0) {
ElNotification({
title: '提示',
message: '请选择所属公司',
@@ -379,6 +406,7 @@ const handleResubmit = () => {
const getDetailInfo = async () => {
getFormInfo(route.query.id).then(res => {
if (res.code === 1000) {
selectedCompanyList.value = getCompanyOptionItem(res.data.companyIds)
formData.value = res.data
showTinymce.value = false
showTable.value = false
@@ -432,6 +460,21 @@ onMounted(async () => {
width: 750px;
}
.company-style {
//width: 98%;
min-height: 30px;
max-height: 60px;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
}
.company {
color: #fff;
height: auto;
}
}
:deep(.el-table--fit ) {

View File

@@ -47,7 +47,7 @@ const getCompanyOptionItem = (val) => {
matterTree(companyNameArray.value, companyOption.value, item)
})
}
return companyNameArray.value.join('');
return companyNameArray.value
}
const init = async () => {
if (!route.query.id) return;

View File

@@ -36,7 +36,7 @@ const searchConfig = reactive([
placeholder: '请选择征集类型',
clearable: true,
filterable: true,
cacheKey: 'todo_type'
cacheKey: 'collect_type'
}
},
{
@@ -61,10 +61,10 @@ const auths = {
}
const tableConfig = reactive({
columns: [
{
type: 'selection',
prop: 'selection'
},
// {
// type: 'selection',
// prop: 'selection'
// },
{
prop: 'requirementName',
label: '征集名称',

View File

@@ -237,8 +237,8 @@
@getOtherFile="getOtherFile" :showFileList="true" :formData="formData"
:preview="name === 'Summary/edit'"/>
<div class="approval-record">
<div style="display: flex;align-items: center;margin-bottom: 20px">
<baseTitle title="流程图"></baseTitle>
<div style="display: flex;align-items: center;justify-content: flex-end;">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color: #13ce66; --el-switch-off-color:#BEA266;margin-left: 10px"
@@ -482,6 +482,7 @@ const getDetailInfo = async () => {
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
res.data.formData.specialFundId= res.data.formData.specialFundId===0?null:res.data.formData.specialFundId
formData.value = res.data.formData
loading.value = false
}

View File

@@ -10,10 +10,10 @@ const tableIns = ref()
const router = useRouter()
const searchConfig = reactive([
{
label: '需求名称',
label: '征集名称',
prop: 'requirementName',
props: {
placeholder: '请输入需求名称',
placeholder: '请输入征集名称',
clearable: true,
checkStrictly: true
},
@@ -34,7 +34,7 @@ const searchConfig = reactive([
},
{
label: '研发主体',
prop: 'productMainBody',
prop: 'rdSubject',
component: shallowRef(fvSelect),
props: {
placeholder: '请选择研发主体',
@@ -46,9 +46,14 @@ const searchConfig = reactive([
},
// {
// label: '项目影响',
// prop: 'projectEffect',
// prop: 'projectImpact',
// component: shallowRef(fvSelect),
// props: {},
// props: {
// placeholder: '请选择项目影响',
// cacheKey: 'project_impact',
// clearable: true,
// filterable: true
// },
// colProps: {}
// },
// {
@@ -78,10 +83,10 @@ const auths = {
}
const tableConfig = reactive({
columns: [
{
type: 'selection',
prop: 'selection'
},
// {
// type: 'selection',
// prop: 'selection'
// },
{
prop: 'requirementName',
label: '征集名称',

View File

@@ -20,7 +20,7 @@ const router = useRouter()
const activeName = ref('50')
const attachment = ref({})
const loading = ref(false)
const uploadState = ref(true)
const uploadState = ref(false)
const fileList = ref([])
const projectId = ref(route.query.id)
const requirementId = ref(route.query.requirementId)
@@ -43,26 +43,26 @@ const schema = computed(() => {
]
})
const baseForm = ref()
const paneList=ref([
const paneList = ref([
{
label:'需求征集',
name:'00'
label: '需求征集',
name: '00'
},
{
label:'需求上报',
name:'10'
label: '需求上报',
name: '10'
},
{
label:'项目立项',
name:'20'
label: '项目立项',
name: '20'
},
{
label:'项目实施',
name:'40'
label: '项目实施',
name: '40'
},
{
label:'项目归档',
name:'50'
label: '项目归档',
name: '50'
}
])
const getBaseInfo = async () => {
@@ -75,16 +75,19 @@ const getBaseInfo = async () => {
getBaseInfo()
const handleClick = (tab) => {
activeName.value=tab.props.name
loading.value=true
activeName.value = tab.props.name
loading.value = true
search({})
}
const search = async (param) => {
param.targetState = activeName.value
if (activeName.value === '00') {
param.requirementId = requirementId.value
}
param.targetId = projectId.value
param.targetState = activeName.value
searchFileList(param).then(res => {
loading.value=false
loading.value = false
changeFileList(res)
})
}

View File

@@ -10,6 +10,8 @@
<script setup lang="jsx">
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
import {toThousands} from '@/utils/changePrice.js'
import {switchAttachmentState} from "@/api/project-manage/attachment";
import {ElMessageBox} from "element-plus";
const router = useRouter()
const shortcuts = [
@@ -244,6 +246,12 @@ const tableConfig = reactive({
if (buttons.has("edit")) {
btn.push({label: '编辑', prem: ['project:management:filing:conclusion'], func: () => handleEdit(row), type: 'primary'})
}
if (buttons.has("openFileSwitch")) {
btn.push({label: '开启上传', prem: ['project:management:filing:conclusion'], func: () => handleOpenUpload(row,true), type: 'primary'})
}
if (buttons.has("closeFileSwitch")) {
btn.push({label: '关闭上传', prem: ['project:management:filing:conclusion'], func: () => handleOpenUpload(row,false), type: 'primary'})
}
return (
<div style={{width: '100%'}}>
{
@@ -316,4 +324,19 @@ const handleEdit = (row) => {
}
})
}
const handleOpenUpload=(row,flag)=>{
ElMessageBox.confirm(`是否确认${flag?'开启':'关闭'}上传文件?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params={
open: flag,
projectId: row.projectId
}
switchAttachmentState(params).then(res=>{
tableIns.value.refresh()
})
})
}
</script>

View File

@@ -2,6 +2,7 @@
<baseTitle title="基础信息"></baseTitle>
<fvForm :schema="schema" @getInstance="(e)=>baseForm = e"></fvForm>
<fvSearchForm :searchConfig="searchConfig" @search="search"></fvSearchForm>
<el-button @click="exportExcelHandler">导出</el-button>
<fvTable ref="tableIns" :tableConfig="tableConfig" @headBtnClick="headBtnClick">
<template #empty>
<el-empty description="暂无数据"/>
@@ -12,42 +13,107 @@
<script setup lang="jsx">
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
import {toThousands} from '@/utils/changePrice.js'
import {computed, ref} from "vue";
import {getBaseInfoApi} from "@/components/steps/api";
import {searchUpdateLedgerData,exportExcel} from "@/api/project-manage";
const router = useRouter()
const route = useRoute()
const schema = computed(() => {
return [
{
label: '征集名称',
prop: 'requirementName',
colProps: {
span: 12
}
},
{
label: '项目名称',
prop: 'projectName',
colProps: {
span: 12
}
const formArray = ref([
{
label: '征集名称',
prop: 'requirementName',
colProps: {
span: 12
}
]
})
const baseForm = ref()
const searchConfig = reactive([
},
{
label: '项目名称',
prop: 'projectName',
component: 'el-input',
props: {
placeholder: '请输入项目名称查询',
clearable: true,
filterable: true,
checkStrictly: true
colProps: {
span: 12
}
}
])
const formDataArray = ref([
{
label: '征集名称',
prop: 'requirementName',
colProps: {
span: 12
}
},
{
label: '项目名称',
prop: 'projectName',
colProps: {
span: 12
}
},
{
label: '项目负责人',
prop: 'projectChargePerson',
colProps: {
span: 12
}
},
{
label: '项目开始时间',
prop: 'startTime',
colProps: {
span: 12
}
},
{
label: '项目预计持续时间',
prop: 'endTime',
colProps: {
span: 12
}
},
{
label: '项目开展方式',
prop: 'projectDevelopmentWay',
colProps: {
span: 24
}
},
{
label: '项目预算',
prop: 'projectBudgetDescription',
colProps: {
span: 24
}
},
{
label: '项目总体完成率(%',
prop: 'projectCompletionRate',
colProps: {
span: 6
}
},
{
label: '已完成工作量',
prop: 'completeWork',
colProps: {
span: 18
}
}
])
const tableData = ref({})
const schema = computed(() => {
if (JSON.stringify(tableData.value) !== '{}') {
return formDataArray.value
} else {
return formArray.value
}
})
const baseForm = ref()
const tableIns = ref()
const btns = ref([
{name: '表格更新', key: 'update', color: '#DED0B2', auth: ''}
])
const searchConfig = reactive([
{
label: '时间',
prop: 'time',
@@ -58,9 +124,10 @@ const searchConfig = reactive([
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
colProps: {}
}, {
},
{
label: '项目费用',
prop: 'requirementName',
prop: 'projectCost',
component: shallowRef(fvSelect),
props: {
placeholder: '请选择项目费用查询',
@@ -68,16 +135,17 @@ const searchConfig = reactive([
filterable: true,
cacheKey: 'project_cost',
}
}, {
label: '项目阶段',
},
{
label: '研发阶段',
prop: 'researchStage',
component: shallowRef(fvSelect),
props: {
placeholder: '请选择项目阶段查询',
placeholder: '请选择研发阶段查询',
clearable: true,
filterable: true,
checkStrictly: true,
cacheKey: 'research_stage',
cacheKey: 'fee_stage',
}
},
{
@@ -109,7 +177,7 @@ const tableConfig = reactive({
prop: 'name',
type: 'index',
label: '序号',
width:'80',
width: '80',
align: 'center'
},
{
@@ -121,13 +189,10 @@ const tableConfig = reactive({
prop: 'projectCost',
label: '项目费用',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.projectCost !== null&&row.projectCost !== null&&row.projectCost!==undefined) {
if(typeof Number(row.projectCost) === 'number'){
return '--'
}else {
return (<Tag dictType={'project_cost'} value={row.projectCost}/>)
}
if (row.projectCost !== null && row.projectCost !== null && row.projectCost !== undefined) {
return (<Tag dictType={'project_cost'} value={row.projectCost}/>)
} else {
return '--'
}
@@ -135,10 +200,11 @@ const tableConfig = reactive({
},
{
prop: 'researchStage',
label: '项目阶段',
label: '研发阶段',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.researchStage&&row.researchStage !== null&&row.researchStage!==undefined) {
if (row.researchStage && row.researchStage !== null && row.researchStage !== undefined) {
return (<Tag dictType={'research_stage'} value={row.researchStage}/>)
} else {
return '--'
@@ -154,20 +220,28 @@ const tableConfig = reactive({
prop: 'afterTax',
label: '税后余额(元)',
align: 'center',
currentRender:({row})=>{
currentRender: ({row}) => {
return <span>{toThousands(row.afterTax)}</span>
}
}
},
],
api: '/workflow/mosr/expense/ledger',
params: {
projectId:route.query.id
projectId: route.query.id
},
btns: [
{name: '上传费用', key: 'add', color: '#DED0B2',auth: ''}
]
btns: btns.value
})
const tableIns=ref()
if (route.query.state !== '4') {
btns.value.push({name: '上传费用', key: 'add', color: '#DED0B2', auth: ''})
}
const handleUpdateTable = () => {
router.push({
name: 'Implementation/update',
query: {
id: route.query.id
}
})
}
const getBaseInfo = async () => {
try {
const {code, data} = await getBaseInfoApi(route.query.id)
@@ -182,22 +256,58 @@ const headBtnClick = (key) => {
case 'add':
handleUploadFee()
break;
case 'update':
handleUpdateTable()
break;
}
}
const handleUploadFee = () => {
router.push({
name: 'Implementation/uploadFee',
query: {
id:route.query.id
id: route.query.id
}
})
}
const exportExcelHandler = () => {
let data = {
projectId: 113
}
exportExcel(data).then(res => {
console.log(res)
let reg = /filename=([^&]+)/;
let contentDisposition = decodeURI(res.headers['content-disposition'])
let result = reg.exec(contentDisposition)
let fileName = result[1]
fileName = fileName.replace(/\"/g, '')
const blob = new Blob([res.data])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = fileName
a.click()
})
}
const search = (val) => {
console.log('val',val)
tableConfig.params = {...val}
tableConfig.params = {...val, projectId: route.query.id}
tableIns.value.refresh()
}
const init = async () => {
const {code, msg, data} = await searchUpdateLedgerData(route.query.id)
if (data) {
tableData.value = data
baseForm.value.setValues(data)
}
// if (code !== 1000) {
// ElNotification({
// title: '提示',
// message: msg,
// type: 'error'
// })
// }
}
init()
</script>
<style scoped>

View File

@@ -29,15 +29,14 @@
<script setup lang="jsx">
import {downloadFile} from "@/api/project-demand";
import {searchFileList} from "@/api/project-manage/attachment.js";
import {getTags} from "@/api/project-manage";
import {ElLoading, ElNotification} from "element-plus";
import {computed, ref} from "vue";
import {ElNotification} from "element-plus";
import {getBaseInfoApi} from "@/components/steps/api";
import {searchImplementationFileList} from "@/api/project-manage/attachment";
const route = useRoute()
const router = useRouter()
const uploadState = ref(true)
const uploadState = ref(false)
const attachment = reactive({
tag: ''
})
@@ -140,7 +139,7 @@ const handleSearch = () => {
})
params.tag = attachment.tag
}
searchFileList(params).then(res => {
searchImplementationFileList(params).then(res => {
showTable.value = false
if (res.code === 1000) {
otherFileList.value = res.data.fileList

View File

@@ -44,6 +44,7 @@
:formData="detailData.formData"/>
</template>
</steps>
<div style="width: 100%;height: 30px"></div>
<opinion v-if="detailData.taskId" :formData="detailData.formData" :taskId="detailData.taskId"
v-model:value="auditOpinion"/>
</template>

View File

@@ -93,7 +93,7 @@ const searchConfig = reactive([
component: 'el-date-picker',
props: {
clearable: true,
type: 'datetimerange',
type: 'daterange',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
@@ -136,10 +136,10 @@ const searchConfig = reactive([
const tableIns = ref()
const tableConfig = reactive({
columns: [
{
type: 'selection',
prop: 'selection'
},
// {
// type: 'selection',
// prop: 'selection'
// },
{
prop: 'projectName',
label: '项目名称',
@@ -161,7 +161,7 @@ const tableConfig = reactive({
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.projectType !== null) {
if (row.projectType && row.projectType !== null && row.projectType !== undefined) {
return (<Tag dictType={'project_type'} value={row.projectType}/>)
} else {
return '--'
@@ -174,7 +174,7 @@ const tableConfig = reactive({
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.rdSubject !== null) {
if (row.rdSubject && row.rdSubject !== null && row.rdSubject !== undefined) {
return (<Tag dictType={'rd_subject'} value={row.rdSubject}/>)
} else {
return '--'
@@ -183,11 +183,11 @@ const tableConfig = reactive({
},
{
prop: 'researchStage',
label: '项目阶段',
label: '研发阶段',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.researchStage&&row.researchStage !== null&&row.researchStage!==undefined) {
if (row.researchStage && row.researchStage !== null && row.researchStage !== undefined) {
return (<Tag dictType={'research_stage'} value={row.researchStage}/>)
} else {
return '--'
@@ -200,7 +200,7 @@ const tableConfig = reactive({
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.projectImpact !== null) {
if (row.projectImpact && row.projectImpact !== null && row.projectImpact !== undefined) {
return (<Tag dictType={'project_impact'} value={row.projectImpact}/>)
} else {
return '--'
@@ -234,7 +234,7 @@ const tableConfig = reactive({
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.state !== null) {
if (row.state && row.state !== null && row.state !== undefined) {
return (<Tag dictType={'project_implementation'} value={row.state}/>)
} else {
return '--'
@@ -344,11 +344,11 @@ const handleEdit = (row) => {
})
}
const handleStandingBook = (row) => {
localStorage.setItem('projectName', row.projectName)
router.push({
name: 'Implementation/account',
query: {
id: row.projectId
id: row.projectId,
state:row.state
}
})
}

View File

@@ -13,8 +13,8 @@
@getOtherFile="getOtherFile" :showFileList="true" :formData="formData"
:preview="name === 'Phase/edit'"/>
<div class="approval-record">
<div style="display: flex;align-items: center;margin-bottom: 20px">
<baseTitle title="流程图"></baseTitle>
<div style="display: flex;align-items: center;justify-content: flex-end;">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color: #13ce66; --el-switch-off-color:#BEA266;margin-left: 10px"
@@ -101,11 +101,11 @@ const compositeParam = (item) => {
}
}
const getAttachment = (val) => {
console.log('上传文件getAttachment', val)
// console.log('上传文件getAttachment', val)
formData.value.singleFile = compositeParam(val)
}
const getOtherFile = (val) => {
console.log('上传文件getOtherFile', val)
// console.log('上传文件getOtherFile', val)
showTable.value = false
let fileObj = compositeParam(val)
otherFileList.value.push(fileObj)
@@ -223,7 +223,7 @@ const handleResubmit = (instance) => {
projectId: route.query.projectId,
userIds: userIds
}
console.log('重新提交params', params)
// console.log('重新提交params', params)
resubmitPhaseForm(params).then(res => {
ElNotification({
title: '提示',

View File

@@ -59,7 +59,7 @@ const getInfo = async () => {
const {code, data, msg} = await getPhaseDetail(projectId)
if (code === 1000) {
summaryData.value = data;
copyName.value= data.formData.userInfoList.map(item=>item.name).join('')
copyName.value= data.formData.userInfoList?.map(item=>item.name).join('')
loading.value = false
processStore.setDesign(data)
processStore.runningList.value = data.runningList;

View File

@@ -0,0 +1,163 @@
<template>
<baseTitle title="表格更新"></baseTitle>
<el-form :model="tableForm" ref="form">
<el-row>
<el-col :span="24">
<el-form-item prop="projectName" label="项目名称">
<span>{{ tableForm.projectName }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item prop="projectChargePerson" label="项目负责人">
{{tableForm.projectChargePerson?tableForm.projectChargePerson: currentPerson.name }}
<el-button @click="showPersonnelPicker">
{{ tableForm.projectChargePerson||currentPerson.name ? '更改' : '请选择研发人员' }}
</el-button>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="startTime" label="项目开始时间">
<el-date-picker
v-model="tableForm.startTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="选择项目开始时间"
>
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="endTime" label="项目预计持续时间" :title="!tableForm.startTime?'请先选择项目开始时间!':''">
<el-date-picker
v-model="tableForm.endTime"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="选择项目预计持续时间"
:disabled="!tableForm.startTime"
:disabled-date="disabledDate"
>
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item prop="projectDevelopmentWay" label="项目开展方式" style="width: 100%">
<el-input v-model="tableForm.projectDevelopmentWay" placeholder="请输入项目开展方式" clearable>
</el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item prop="projectBudgetDescription" label="项目预算" style="width: 100%">
<el-input v-model="tableForm.projectBudgetDescription" placeholder="请输入项目预算" clearable>
</el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="projectCompletionRate" label="项目总体完成率(%">
<el-input-number v-model="tableForm.projectCompletionRate" placeholder="请输入项目总体完成率" :controls="false" style="width: 200px">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="16" :offset="1">
<el-form-item prop="completeWork" label="已完成工作量">
<el-input v-model="tableForm.completeWork" placeholder="请输入已完成工作量" clearable>
</el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<user-picker :multiple="false" ref="userPicker" title="请选择项目负责人" @ok="selected"/>
<div class="oper-page-btn">
<el-button color="#DED0B2" @click="handleSubmit">提交</el-button>
<el-button @click="handleBack">返回</el-button>
</div>
</template>
<script setup lang="jsx">
import {ElMessage, ElNotification} from "element-plus";
import {updateLedger} from "@/api/project-manage";
import {getBaseInfoApi} from "@/components/steps/api";
import {ref} from "vue";
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
import {useTagsView} from '@/stores/tagsview.js'
import {searchUpdateLedgerData} from "@/api/project-manage";
const tagsViewStore = useTagsView()
const baseForm = ref()
const route = useRoute()
const router = useRouter()
const currentPerson = ref({})
const tableForm = ref({
projectName: '',
completeWork: '',
endTime: '',
projectBudgetDescription: '',
projectChargePerson: '',
projectCompletionRate: '',
projectDevelopmentWay: '',
projectId: '',
startTime: '',
})
const userPicker = ref()
const selected = (select) => {
for (const selectElement of select) {
currentPerson.value = selectElement
tableForm.value.projectChargePerson = selectElement.id
}
}
const disabledDate = (time) => {
return time.getTime() < new Date(tableForm.value.startTime).getTime();
}
const handleBack = () => {
history.back()
}
const showPersonnelPicker = () => {
userPicker.value.showUserPicker()
}
const handleSubmit = async () => {
let params = {
...tableForm.value,
projectId: route.query.id
}
updateLedger(params).then(res => {
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Implementation/account',
query: {
id: route.query.id
}
})
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
})
}
const getBaseInfo = async () => {
const {code, data} = await getBaseInfoApi(route.query.id)
tableForm.value.projectName = data.projectName
}
getBaseInfo()
const init = async () => {
const {code, msg, data} = await searchUpdateLedgerData(route.query.id)
tableForm.value = data
if (code !== 1000) {
ElNotification({
title: '提示',
message: msg,
type: 'error'
})
}
}
init()
</script>
<style scoped>
</style>

View File

@@ -3,7 +3,7 @@
<fvForm :schema="schema" @getInstance="(e)=>baseForm = e"></fvForm>
<el-form :model="tableForm" ref="form" class="query-form">
<el-table :data="tableForm.tableData" style="width: 100%">
<el-table-column prop="time" label="时间">
<el-table-column prop="time" label="时间" width="180">
<template #default="scope">
<el-form-item prop="time" :rules="scope.row.time?'1':rules.time">
<el-date-picker
@@ -17,7 +17,7 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="projectCost" label="项目费用">
<el-table-column prop="projectCost" label="项目费用" width="220">
<template #default="scope">
<el-form-item prop="projectCost" :rules="scope.row.projectCost?'1':rules.projectCost">
<el-select v-model="scope.row.projectCost" placeholder="请选择费用性质" clearable filterable>
@@ -31,10 +31,10 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="researchStage" label="项目阶段">
<el-table-column prop="researchStage" label="研发阶段" width="220">
<template #default="scope">
<el-form-item prop="researchStage" :rules="scope.row.researchStage?'1':rules.researchStage">
<el-select v-model="scope.row.researchStage" placeholder="请选择项目阶段" clearable filterable>
<el-select v-model="scope.row.researchStage" placeholder="请选择研发阶段" clearable filterable>
<el-option
v-for="item in cacheStore.getDict('fee_stage')"
:key="item.value"
@@ -45,7 +45,7 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="digest" label="摘要">
<el-table-column prop="digest" label="摘要" width="220">
<template #default="scope">
<el-form-item prop="digest" :rules="scope.row.digest?'1':rules.digest">
<el-input v-model="scope.row.digest" placeholder="请输入摘要" clearable>
@@ -53,11 +53,11 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="afterTax" label="税后余额(元)">
<el-table-column prop="afterTax" label="税后余额(元)" width="220">
<template #default="scope">
<el-form-item prop="afterTax" :rules="scope.row.afterTax?'1':rules.afterTax">
<el-input v-model="scope.row.afterTax" placeholder="请输入税后余额" clearable>
</el-input>
<el-input-number v-model="scope.row.afterTax" placeholder="请输入税后余额" :controls="false">
</el-input-number>
</el-form-item>
</template>
</el-table-column>
@@ -115,7 +115,7 @@ const baseForm = ref()
const rules = reactive({
time: [{required: true, message: '请选择时间', trigger: 'blur'}],
projectCost: [{required: true, message: '请输入项目费用', trigger: 'blur'}],
researchStage: [{required: true, message: '请输入项目阶段', trigger: 'blur'}],
researchStage: [{required: true, message: '请输入研发阶段', trigger: 'blur'}],
digest: [{required: true, message: '请输入摘要', trigger: 'blur'}],
afterTax: [{required: true, message: '请输入税后余额', trigger: 'blur'}]
})
@@ -127,7 +127,7 @@ const tableForm = reactive({
projectCost: '',
researchStage: '',
digest: '',
afterTax: ''
afterTax: null
}
]
})
@@ -148,7 +148,7 @@ const handleAdd = () => {
projectCost: '',
researchStage: '',
digest: '',
afterTax: ''
afterTax: null
}
tableForm.tableData.push(row)
}
@@ -184,4 +184,15 @@ const handleBack = () => {
history.back()
}
</script>
<style scoped lang="scss">
:deep(.el-table--enable-row-transition) {
.el-table__body td.el-table__cell {
.cell {
.el-form-item {
margin-top: 20px;
}
}
}
}
</style>

View File

@@ -91,7 +91,7 @@ const searchConfig = reactive([
component: 'el-date-picker',
props: {
clearable: true,
type: 'datetimerange',
type: 'daterange',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
valueFormat: 'YYYY-MM-DD HH:mm:ss',

View File

@@ -0,0 +1,272 @@
<template>
<div v-loading="loading">
<fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>
<el-form :model="formData" label-width="auto">
<file-component :title="getTagName(type)+'附件'" :tag="getTagName(type)"
v-model:value="formData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
</el-form>
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
<div class="approval-record">
<div class="approval-title">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color: #13ce66; --el-switch-off-color:#BEA266"
/>
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" :id-name="idName?idName:type"/>
</div>
</div>
</div>
</template>
<script setup lang="jsx">
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
import {ElLoading} from 'element-plus';
import {downloadFile} from "@/api/project-demand";
const changeDiagram = ref(false)
const props = defineProps({
formData: {
type: Object,
default: {}
},
data: {
type: Object,
default: {}
},
processViewer: {
type: Boolean,
default: false
},
companyOption: {
type: Array,
default: []
},
fileListShow: {
type: String,
default: 'READ'
},
// approval 立项, execute 实施, 归档 archivist
type: {
type: String,
default: 'approval'
},
loading: {
type: Boolean,
default: false
},
value: {
type: String,
default: ''
},
idName: {
type: String,
default: ''
}
})
const form = ref()
const schema = computed(() => {
let arr
if (props.type == 'approval') {
arr = [
{
label: '前置流程',
prop: 'preProcess',
colProps: {
span: 24
},
component: () => (
<div>
{
props.formData.preProcess ? props.formData.preProcess.map(item => {
return <span><a target="_blank" style={{color: '#409EFF', cursor: 'pointer'}}
href={props.formData.preProcessBaseUrl + item.requestId}>{item.requestName}</a> </span>
}) : <span>{'--'}</span>
}
</div>
)
},
{
label: '项目立项附件',
prop: 'singleFile',
colProps: {
span: 24
},
component: () => (
<div>
{
props.formData.singleFile?.originalFileName ?
<span
style={{color: '#409EFF', cursor: 'pointer'}}
onClick={() => handleDownload(props.formData.singleFile)}
>
{props.formData.singleFile?.originalFileName}
</span> :
<span>{'--'}</span>
}
</div>
)
},
]
} else if (props.type == 'execute') {
arr = [
{
label: '前置流程',
prop: 'preProcess',
colProps: {
span: 24
},
component: () => (
<div>
{
props.formData.preProcess ? props.formData.preProcess.map(item => {
return <span><a target="_blank" style={{color: '#409EFF', cursor: 'pointer'}}
href={props.formData.preProcessBaseUrl + item.requestId}>{item.requestName}</a> </span>
}) : <span>{'--'}</span>
}
</div>
)
},
{
label: '项目验收附件',
prop: 'singleFile',
colProps: {
span: 24
},
component: () => (
<div>
{
props.formData.singleFile?.originalFileName ?
<span
style={{color: '#409EFF', cursor: 'pointer'}}
onClick={() => handleDownload(props.formData.singleFile)}
>
{props.formData.singleFile?.originalFileName}
</span> :
<span>{'--'}</span>
}
</div>
)
},
]
} else if (props.type == 'archivist') {
arr = [
{
label: '项目归档附件',
prop: 'singleFile',
colProps: {
span: 24
},
component: () => (
<div>
{
props.formData.singleFile?.originalFileName ?
<span
style={{color: '#409EFF', cursor: 'pointer'}}
onClick={() => handleDownload(props.formData.singleFile)}
>
{props.formData.singleFile?.originalFileName}
</span> :
<span>{'--'}</span>
}
</div>
)
},
]
} else if (props.type == 'phase') {
arr = [
{
label: '阶段变更附件',
prop: 'singleFile',
colProps: {
span: 24
},
component: () => (
<div>
{
props.formData.singleFile?.originalFileName ?
<span
style={{color: '#409EFF', cursor: 'pointer'}}
onClick={() => handleDownload(props.formData.singleFile)}
>
{props.formData.singleFile?.originalFileName}
</span> :
<span>{'--'}</span>
}
</div>
)
},
]
}
return arr
})
const emit = defineEmits(['update:value'])
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const getTagName = (type) => {
switch (type) {
case 'approval':
return '项目立项'
case 'execute':
return '项目实施'
case 'archivist':
return '项目归档'
case 'phase':
return '阶段变更'
}
}
const handleDownload = (row) => {
const loading = ElLoading.service({fullscreen: true})
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
loading.close()
})
}
watchEffect(() => {
Object.keys(props.formData).length && (form.value?.setValues(props.formData))
})
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,192 @@
<template>
<div v-loading="loading">
<el-form :model="formData" label-width="auto">
<el-row>
<el-col :span="24" v-if="type==='singleDetail'">
<el-form-item label="征集名称">
<span>{{ formData.requirementName }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="征集类型">
<span>{{ formData.collectType }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="截止时间">
<span>{{ formData.deadline }}</span>
</el-form-item>
</el-col>
<el-col :span="24" v-if="type==='singleDetail'">
<el-form-item label="所属公司">
<span :class="showExpendClass(showMoreCompany,formData.companyIds)">{{
getCompanyName(formData.companyIds)
}}</span>
<div style="color: #2a99ff;text-align: center;width: 100%;font-size: 15px;cursor: pointer"
@click="handleExpend">{{ showExpendText }}
</div>
</el-form-item>
</el-col>
<el-col :span="24" v-if="formData.isSpecialFund">
<el-form-item label="专项资金">
<span>{{ formData.specialFund }}</span>
</el-form-item>
</el-col>
<baseTitle title="征集说明"></baseTitle>
<el-col :span="24">
<el-form-item>
<el-card style="width: 100%">
<div v-html="formData.collectExplain">
</div>
</el-card>
</el-form-item>
</el-col>
<baseTitle v-if="fileListShow === 'READ' || fileListShow === 'EDIT'" title="附件列表"></baseTitle>
<el-col :span="24">
<file-component title="" tag="需求征集"
v-model:value="formData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
</el-col>
<el-col :span="24">
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
</el-col>
</el-row>
<div class="approval-record">
<div class="approval-title">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color: #13ce66; --el-switch-off-color:#BEA266"
/>
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="collectionProcess"/>
</div>
</div>
</el-form>
</div>
</template>
<script setup lang="jsx">
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {downloadFile} from "@/api/project-demand";
const emit = defineEmits(['update:value'])
const showExpendText = ref('')
const showMoreCompany = ref(false)
const props = defineProps({
formData: {
type: Array,
default: []
},
data: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
},
companyOption: {
type: Array,
default: []
},
loading: {
type: Boolean,
default: false
},
fileListShow: {
type: String,
default: ''
},
type: {
type: String,
default: ''
},
value: {
type: String,
default: ''
}
})
const changeDiagram = ref(false)
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const getCompanyName = (data) => {
if (data) {
return data.join('')
}
}
const handleExpend = () => {
showMoreCompany.value = !showMoreCompany.value;
showExpendClass(showMoreCompany.value, props.formData.companyIds)
}
const showExpendClass = (showMoreCompany, data) => {
if (!showMoreCompany) {
if (data && data.length > 14) {
showExpendText.value = '展开'
return 'company-style'
}
} else {
showExpendText.value = '收缩'
return ''
}
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
:deep(.el-empty__description) {
margin-top: 0;
}
.company-style {
//width: 98%;
min-height: 30px;
max-height: 60px;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
}
</style>

View File

@@ -0,0 +1,168 @@
<template>
<!-- <baseTitle title="审核意见"></baseTitle>-->
<!-- <fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>-->
<div class="oper-page-btn">
<el-button type="danger" @click="handleReject">驳回</el-button>
<el-button color="#DED0B2" @click="handleAgree">同意</el-button>
</div>
</template>
<script setup lang="jsx">
import {ElNotification} from 'element-plus';
import {agreeTask, rejectTask} from "@/api/project-demand/index.js";
import {useTagsView} from '@/stores/tagsview.js'
const tagsViewStore = useTagsView()
const route = useRoute()
const router = useRouter()
const props = defineProps({
taskId: {
type: String,
default: ''
},
formData: {
type: Object,
default: {}
},
value: {
type: String,
default: ''
}
})
const form = ref()
const schema = computed(() => {
return [
{
label: '',
prop: 'auditOpinion',
component: 'el-input',
colProps: {
span: 24
},
props: {
placeholder: '请输入审核意见',
type: 'textarea',
rows: 3
}
}
]
})
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const back = () => {
switch (route.name) {
case 'Initiation/detail':
router.push({name: 'Initiation'})
break;
case 'Filing/detail':
router.push({name: 'Filing'})
break;
case 'Implementation/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
if (route.query.step === '10') {
router.push({name: 'Summary'})
} else if (route.query.step === '20') {
router.push({name: 'Initiation'})
} else if (route.query.step === '40') {
router.push({name: 'Implementation'})
} else if (route.query.step === '50') {
router.push({name: 'Filing'})
} else if (route.query.step === '00') {
router.push({name: 'Requirement'})
}
}
break;
case 'Summary/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Summary'})
}
break;
case 'Requirement/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Requirement'})
}
break;
case 'Fund/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Fund'})
}
break;
case 'Share/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Expense/share'})
}
break;
case 'Phase/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Implementation'})
}
break;
}
}
// 驳回
const handleReject = async () => {
// const values = form.value.getValues()
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
const params = {
taskId: props.taskId,
// ...values
auditOpinion: _value.value
}
// console.log('params', params)
const res = await rejectTask(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
back()
}
const handleAgree = async () => {
// const values = form.value.getValues()
const params = {
taskId: props.taskId,
formData: props.formData,
auditOpinion: _value.value
}
const res = await agreeTask(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
back()
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,429 @@
<template>
<div class="apply-block">
<el-form :model="localFormData" ref="formRef" label-width="auto" :rules="rules" v-if="step!=='50'">
<el-row>
<el-col :span="24">
<el-form-item label="前置流程" :required="preProcessRequired" prop="requestName">
<div v-for="item in localFormData.preProcess" :key="item.requestId">
<a :href="item.baseUrl" target="_blank"
style="color: #2a99ff;margin-right: 10px;cursor: pointer">{{ item.requestName }}</a>
</div>
<el-button color="#DED0B2" @click="handleShowPreTable">
{{ localFormData.preProcess ? '更改' : '请选择' }}
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<AttachmentUpload ref="attachment" :label="getTitleName(title)+'附件'" :showTable="showTable"
:otherFileList="otherFileList"
@getAttachment="getAttachment"
@getOtherFile="getOtherFile" :showFileList="true" :formData="localFormData"
:preview="mode == 'resubmit'"/>
<div>
<div class="approval-record">
<div class="approval-title">
<baseTitle title="审批记录" v-if="mode === 'resubmit'"></baseTitle>
<div v-else></div>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color: #13ce66; --el-switch-off-color:#BEA266"
/>
</div>
</div>
<div class="process">
<operation-render v-if="mode === 'resubmit'&&!changeDiagram" :operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer mode="view" :idName="title" v-if="processDiagramViewer&&changeDiagram"/>
</div>
</div>
</div>
<div class="oper-page-btn">
<el-button color="#DED0B2" v-if="mode === 'submit'" @click="handleSubmit">提交</el-button>
<el-button color="#DED0B2" v-else-if="mode === 'resubmit'" @click="handleSubmit">重新提交</el-button>
<el-button @click="handleBack">返回</el-button>
</div>
<el-dialog title="前置流程" v-model="showPreTable" width="80%">
<el-form :model="preProcessForm" inline>
<el-form-item label="请求名称">
<el-input v-model="preProcessForm.requestName" placeholder="请输入请求名称" clearable>
</el-input>
</el-form-item>
<el-form-item>
<el-button color="#DED0B2" @click="searchPreProcess">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="preProcessList" stripe v-loading="loading"
@select="handleSelect" row-key="requestId">
<el-table-column type="selection" width="55" :reserve-selection="true"/>
<el-table-column prop="requestId" label="请求id"></el-table-column>
<el-table-column prop="requestName" label="请求名称"></el-table-column>
<el-table-column prop="lastOperatorName" label="最后操作人名称"></el-table-column>
<el-table-column prop="lastOperateTime" label="最后操作时间"></el-table-column>
<el-table-column prop="currentNodeName" label="当前节点"></el-table-column>
<el-table-column prop="creatorName" label="创建人"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<!-- <el-button type="primary" @click="choosePreProcess(scope.row)" link>选择</el-button>-->
<a :href="scope.row.baseUrl" target="_blank" style="color: #2a99ff;margin-left: 10px">查看流程</a>
</template>
</el-table-column>
</el-table>
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
:total="total" @changeSize="handleSizeChange" @goPage="handleCurrentChange"/>
<div class="oper">
<el-button color="#DED0B2" @click="choosePreProcess">确定</el-button>
<el-button @click="handleCancel">取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup lang="jsx">
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
import {ElNotification} from "element-plus";
import {
getApplyProcess,
getPreProcess,
getProjectCheckProcess,
getProjectConclusionProcess,
projectApply,
projectCheck,
projectConclusion,
resubmitApply,
resubmitCheck,
resubmitConclusion
} from "@/api/project-manage";
import {useProcessStore} from '@/stores/processStore.js';
import {useTagsView} from '@/stores/tagsview.js'
import Paging from "@/components/pagination/index.vue";
const router = useRouter()
const route = useRoute()
const changeDiagram = ref(false)
const emit = defineEmits(["getAttachment", "getOtherFile"])
const props = defineProps({
title: {
type: String,
default: 'apply'
},
showTable: {
type: Boolean,
default: false
},
mode: {
type: String,
default: "view"
},
data: {
type: Object,
default: {}
},
formData: {
type: Object,
default: {}
},
step: {
type: String,
default: "20"
}
})
const preProcessList = ref([])
//暂存数据
const currentList = ref([])
const preProcessRequired = ref(false)
const total = ref(0)
const preProcessForm = reactive({
requestName: ''
})
const pageInfo = reactive({
pageNum: 1,
pageSize: 10,
})
const rules = reactive({
requestName: [{required: true, message: '请选择前置流程', trigger: 'blur'}],
})
const tagsViewStore = useTagsView()
const processStore = useProcessStore()
const otherFileList = ref([])
const localFormData = ref({
preProcess: [
// {
// requestId: null,
// requestName: '',
// baseUrl: ''
// }
]
})
const attachment = ref()
const deploymentData = ref({})
const showPreTable = ref(false)
const showTable = ref(true)
const loading = ref(false)
const processDiagramViewer = ref(false)
const name = ref(router.currentRoute.value.name)
const deploymentId = ref()
const selectRows = ref([])
const projectId = ref(route.query.projectId)
const getPreProcessUrl = (list) => {
// list.map(item => {
// item.baseUrl = getPreProcessUrl(item.preProcess)
// })
// let baseUrl=
// list.forEach(item => {
// baseUrl=item.baseUrl
// })
// return baseUrl
}
const handleSelect = async (selection) => {
selectRows.value = selection
}
const handleCancel = () => {
showPreTable.value = false
}
const searchPreProcess = () => {
getPreProcessList()
}
const handleReset = () => {
preProcessForm.requestName = ''
getPreProcessList()
}
const handleShowPreTable = () => {
showPreTable.value = true
getPreProcessList()
}
const getPreProcessList = () => {
loading.value = true
getPreProcess().then(res => {
loading.value = false
let searchArray = []
let regexPattern = ("%" + preProcessForm.requestName + "%").replace(/%/g, '.*').replace(/_/g, '.');
let regex = new RegExp('^' + regexPattern + '$');
res.data.filter((item) => {
if (regex.test(item.requestName)) {
searchArray.push(item)
}
})
total.value = searchArray.length
currentList.value = searchArray
preProcessList.value = currentList.value.slice(0, 10)
})
}
const choosePreProcess = () => {
let preProcessObj = {}
let preProcessArray = []
selectRows.value.forEach((item) => {
preProcessObj = {
requestId: item.requestId,
requestName: item.requestName,
baseUrl: item.baseUrl
}
preProcessArray.push(preProcessObj)
})
localFormData.value.preProcess = preProcessArray
// console.log('localFormData.value.preProcess', localFormData.value.preProcess)
showPreTable.value = false
}
//切换每页显示条数
const handleSizeChange = (val) => {
pageInfo.pageSize = val;
preProcessList.value = currentList.value.slice((pageInfo.pageNum - 1) * val, pageInfo.pageNum * val)
};
//点击页码进行分页功能
const handleCurrentChange = (val) => {
pageInfo.pageNum = val;
preProcessList.value = currentList.value.slice((val - 1) * pageInfo.pageSize, val * pageInfo.pageSize)
};
const getTitleName = (type) => {
switch (type) {
case 'apply':
return '项目立项'
case 'check':
return '项目验收'
case 'filing':
return '项目归档'
}
}
const handleBack = () => {
history.back()
}
const compositeParam = (item) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: getTitleName(props.title)
}
}
const getAttachment = (val) => {
// console.log('上传文件getAttachment', val)
localFormData.value.singleFile = compositeParam(val)
}
const getOtherFile = (val) => {
// console.log('上传文件getOtherFile', val)
showTable.value = false
let fileObj = compositeParam(val)
otherFileList.value.push(fileObj)
nextTick(() => {
showTable.value = true
})
}
const getFileParam = (item) => {
return {
fileId: item.fileId,
tag: item.tag
}
}
const handleSubmit = async () => {
if (deploymentData.value.deploymentName === '重大项目立项' || deploymentData.value.deploymentName === '重大项目验收') {
if (localFormData.value.preProcess === undefined) {
ElNotification({
title: '提示',
message: '请选择前置流程!',
type: 'error'
})
}
}
let files = []
if (props.mode === 'resubmit') {
attachment.value.allFileList.forEach(item => {
files.push(getFileParam(item))
})
} else {
otherFileList.value.forEach(item => {
files.push(getFileParam(item))
})
}
// if (localFormData.value.singleFile !== undefined) {
// localFormData.value.singleFile = getFileParam(localFormData.value.singleFile)
// }
// console.log('attachment.value.singleFile', attachment.value, attachment.value.singleFile)
// if (localFormData.value.singleFile) {
//
// } else {
if (attachment.value.singleFile == null) {
attachment.value.validate()
ElNotification({
title: '提示',
message: '请上传附件',
type: 'error'
})
return;
} else {
attachment.value.clearValidate()
}
// }
let params = {
deploymentId: deploymentId.value,
requirementId: route.query.id,
fileList: files,
singleFile: attachment.value.singleFile,
projectId: projectId.value,
preProcess: JSON.stringify(localFormData.value.preProcess)
}
// console.log('params', params)
let res
if (props.step === '20') {
if (props.mode === 'resubmit') {
res = await resubmitApply(params)
} else {
res = await projectApply(params)
}
} else if (props.step === '40') {
if (props.mode === 'resubmit') {
res = await resubmitCheck(params)
} else {
res = await projectCheck(params)
}
} else if (props.step === '50') {
if (props.mode === 'resubmit') {
res = await resubmitConclusion(params)
} else {
res = await projectConclusion(params)
}
}
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
if (props.step === '20') {
await router.push({
name: 'Initiation'
})
} else if (props.step === '40') {
await router.push({
name: 'Implementation'
})
} else if (props.step === '50') {
await router.push({
name: 'Filing'
})
}
}
}
const init = async () => {
let id = projectId.value
if (!id) return;
processDiagramViewer.value = false
let res
if (props.step === '20') {
res = await getApplyProcess(id)
} else if (props.step === '40') {
res = await getProjectCheckProcess(id)
} else if (props.step === '50') {
res = await getProjectConclusionProcess(id)
}
if (res.code === 1000) {
let data = res.data
deploymentId.value = data.deploymentId
deploymentData.value = data
preProcessRequired.value = data.deploymentName === '重大项目立项' || data.deploymentName === '重大项目验收';
processStore.setDesign(data)
processStore.runningList.value = data.runningList;
processStore.endList.value = data.endList;
processStore.noTakeList.value = data.noTakeList;
processStore.refuseList.value = data.refuseList;
processStore.passList.value = data.passList;
nextTick(() => {
processDiagramViewer.value = true
})
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
}
watchEffect(() => {
return Object.keys(props.formData).length && (localFormData.value = props.formData)
})
onMounted(async () => {
await init()
})
</script>
<style scoped>
.oper {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
</style>

View File

@@ -0,0 +1,314 @@
<template>
<baseTitle title="基础信息"></baseTitle>
<fvForm :schema="schema" @getInstance="(e)=>baseForm = e"></fvForm>
<baseTitle title="各流程信息"></baseTitle>
<div class="steps-box">
<el-steps :active="localActive" finish-status="success">
<el-step
v-for="(item, index) in localSteps"
:key="item.key"
:title="item.title"
:class="stepClass(index)"
@click="handleStep(item.key, index)"
/>
</el-steps>
</div>
<!-- 步骤内容 -->
<div>
<slot name="content" :localActive="localActive"></slot>
<!-- <template v-for="(item, index) in stepList" :key="item.key">
<component v-if="localActive == index" v-bind="item.props || {}" :is="item.component" />
</template> -->
</div>
</template>
<script setup lang="jsx">
import {ElLoading, ElNotification} from 'element-plus';
import {computed, reactive, ref, watchEffect} from 'vue';
import {useRoute} from 'vue-router';
import {getBaseInfoApi} from './api';
const props = defineProps({
// 步骤对应内容list
stepList: {
type: Array,
default: []
},
// 当前显示步骤
active: {
type: Number,
default: 0
},
// 已完成的工作流步骤
stepSuccess: {
type: Array,
default: ['00']
},
//直接上报/需求征集
reportType: {
type: String,
default: ''
}
})
const route = useRoute()
const emits = defineEmits(['stepChange', 'setDetail'])
const localData = reactive({})
const localActive = ref(0) // 当前激活步骤
const localSteps = ref([
{
title: '需求征集',
key: 'collect',
},
{
title: '需求上报',
key: 'report',
},
{
title: '项目立项',
key: 'approve',
},
{
title: '项目实施',
key: 'execute',
},
{
title: '项目归档',
key: 'archivist',
},
// {
// title: '项目结项',
// key: 'end',
// },
])
const baseForm = ref()
const schema = computed(() => {
return [
{
label: '征集名称',
prop: 'requirementName',
colProps: {
span: 24
}
},
{
label: '所属公司',
prop: 'affiliatedCompany',
colProps: {
span: 24
}
},
{
label: '项目名称',
prop: 'projectName',
colProps: {
span: 24
}
}
]
})
const localStepSuccess = ref([])
// 格式化详情步骤条
const formatProcedure = (data) => {
let arr = []
if (data instanceof Array) {
data.forEach(item => {
if (props.reportType === 'direct') {
switch (item) {
case '10':
arr.push(0)
break
case '20':
arr.push(1)
break
case '40':
arr.push(2)
break
case '50':
arr.push(3)
break
}
} else {
switch (item) {
case '00':
arr.push(0)
break
case '10':
arr.push(1)
break
case '20':
arr.push(2)
break
case '40':
arr.push(3)
break
case '50':
arr.push(4)
break
}
}
})
}
return arr
}
// 反向格式化
const formatReProcedure = (data) => {
let arr = []
if (data instanceof Array) {
data.forEach(item => {
switch (item) {
case 0:
arr.push('00')
break
case 1:
arr.push('10')
break
case 2:
arr.push('20')
break
// case 3: arr.push('30')
// break
case 3:
arr.push('40')
break
case 4:
arr.push('50')
break
}
})
}
}
const formatActive = (val) => {
let newVal
if (props.reportType === 'direct') {
newVal = val + 1
} else {
newVal = val
}
let active = ''
newVal == 0 && (active = '00')
newVal == 1 && (active = '10')
newVal == 2 && (active = '20')
// val == 3 && (active = '30')
newVal == 3 && (active = '40')
newVal == 4 && (active = '50')
return active
}
const stepClass = (val) => {
if (localStepSuccess.value.includes(val)) {
return 'step-success'
}
return 'step-error'
}
const handleStep = (key, index) => {
if (localStepSuccess.value.includes(index)) {
let active = ''
localActive.value = index
if (props.reportType === 'direct') {
switch (index) {
case 0:
active = '10'
break
case 1:
active = '20'
break
case 2:
active = '40'
break
case 3:
active = '50'
break
}
} else {
switch (index) {
case 0:
active = '00'
break
case 1:
active = '10'
break
case 2:
active = '20'
break
case 3:
active = '40'
break
case 4:
active = '50'
break
}
}
emits('stepChange', {key, active})
return
}
ElNotification({
title: '提示',
message: '不能查看未完成的工作流信息',
type: 'warning'
})
}
const getBaseInfo = async () => {
const loading = ElLoading.service({fullscreen: true})
try {
const {code, data} = await getBaseInfoApi(route.query.projectId)
// console.log('data.procedure',data.procedure,route.query.step)
if(route.query.step==='40'){
if(data.procedure.indexOf('40')==-1){
data.procedure.push('40')
}
}else if(route.query.step==='50'){
if(data.procedure.indexOf('50')==-1){
data.procedure.push('50')
}
}
localStepSuccess.value = formatProcedure(data.procedure)
baseForm.value.setValues(data)
emits('setDetail', formatActive(localActive.value))
loading.close()
} catch {
loading.close()
}
}
getBaseInfo()
watchEffect(() => {
localActive.value = props.active
})
watchEffect(() => {
if (props.reportType === 'direct') {
localSteps.value = localSteps.value.slice(1)
}
})
</script>
<style lang="scss" scoped>
.steps-box {
padding: 10px 0;
}
.step-success {
cursor: pointer;
}
.step-error {
cursor: not-allowed;
}
</style>

View File

@@ -0,0 +1,289 @@
<template>
<div class="detail-block" v-loading="loading">
<el-form :model="localFormData" ref="summaryForm" :rules="rules">
<el-row gutter="50">
<el-col :span="24">
<el-form-item label="项目名称" prop="projectName">
<span>{{ localFormData.projectName }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="专项资金" prop="specialFund" v-if="localFormData.isSpecialFund">
<span>{{localFormData.specialFundId===0?localFormData.specialFund:changeName(fundOption,localFormData.specialFundId) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="开始时间" prop="startTime">
<span>{{ localFormData.startTime }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="结束时间" prop="endTime">
<span>{{ localFormData.endTime }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="项目类型" prop="projectType">
<span>{{ filterDict(cacheStore.getDict('project_type'), localFormData.projectType) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="研发主体" prop="rdSubject">
<span>{{ filterDict(cacheStore.getDict('rd_subject'), localFormData.rdSubject) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="出资类型" prop="investmentType">
<span>{{ filterDict(cacheStore.getDict('invest_type'), localFormData.investmentType) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="项目影响" prop="projectImpact">
<span>{{ filterDict(cacheStore.getDict('project_impact'), localFormData.projectImpact) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="所属业务板块" prop="businessSegment">
<span>{{ filterDict(cacheStore.getDict('business_segment'), localFormData.businessSegment) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预期成果形式" prop="resultForm">
<span>{{ filterDict(cacheStore.getDict('result_form'), localFormData.resultForm) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预期技术标准制定" prop="technicalStandard">
<span>{{ filterDict(cacheStore.getDict('technical_standard'), localFormData.technicalStandard) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="产学研联合" prop="industryUniversityResearch">
<span>{{
filterDict(cacheStore.getDict('industry_university'), localFormData.industryUniversityResearch)
}}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="开展政府申报" prop="governmentDeclaration">
<span>{{
filterDict(cacheStore.getDict('government_declaration'), localFormData.governmentDeclaration)
}}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="知识产权状况" prop="intellectualProperty">
<span>{{
filterDict(cacheStore.getDict('intellectual_property'), localFormData.intellectualProperty)
}}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="发明专利(项)" prop="inventionPatent">
<span>{{ localFormData.inventionPatent }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="实用性新型专利(项)" prop="newPatent">
<span>{{ localFormData.newPatent }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="软件著作权(项)" prop="softwareCopyright">
<span>{{ localFormData.softwareCopyright }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="著作权(项)" prop="copyright">
<span>{{ localFormData.copyright }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="其他(项)" prop="other">
<span>{{ localFormData.other }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="经济概算(元)" prop="economicEstimate">
<span>{{toThousands( localFormData.economicEstimate )}}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="其中申请公司总部科技创新专项资金(元)" prop="specialFundAmount"
v-if="localFormData.isSpecialFund">
<span>{{ toThousands(localFormData.specialFundAmount) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="现有业务描述" prop="serviceDescription">
<span>{{ localFormData.serviceDescription }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="研发项目关键内容描述" prop="contentDescription">
<span>{{ localFormData.contentDescription }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="需求上报申请书">
<el-button type="primary" link @click="handleDownload(localFormData.singleFile)" style="font-size: 16px">
{{ localFormData.singleFile?.originalFileName }}
</el-button>
</el-form-item>
</el-col>
<el-col :span="24">
<file-component title="需求上报附件" tag="需求上报"
v-model:value="localFormData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
</el-col>
<el-col :span="24">
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
</el-col>
</el-row>
<div class="approval-record">
<div class="approval-title">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color: #13ce66; --el-switch-off-color:#BEA266"
/>
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram" :operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="summaryProcess"/>
</div>
</div>
</el-form>
</div>
</template>
<script setup lang="jsx">
import {toThousands} from '@/utils/changePrice.js'
import {downloadFile, deleteFile} from "@/api/project-demand";
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {useTagsView} from '@/stores/tagsview.js'
import {getFundOption} from "@/api/special-fund";
import {useCacheStore} from '@/stores/cache.js'
import {getSubCompOpt} from "@/api/user/user";
import FileComponent from "@/components/DetailComponent/FileComponent.vue";
const emit = defineEmits(['update:value'])
const tagsViewStore = useTagsView()
const cacheStore = useCacheStore()
const props = defineProps({
formData: {
type: Object,
default: {}
},
data: {
type: Object,
default: {}
},
processViewer: {
type: Boolean,
default: false
},
fileListShow: {
type: String,
default: 'READ'
},
loading: {
type: Boolean,
default: false
},
value: {
type: String,
default: ''
}
})
const changeDiagram = ref(false)
const localFormData = ref({})
const router = useRouter()
const fundOption = ref([])
const companyOption = ref([])
const dictName = ref({})
const rules = reactive({
auditOpinion: [{required: true, message: '请输入审核意见', trigger: 'blur'}],
})
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const filterDict = (data, value) => {
if (data === undefined || value === undefined) return;
let label = ''
if (data instanceof Array) {
data.find(item => {
if (item.value == value) {
label = item.label
}
})
}
return label
}
const getFundOptions = async () => {
const resFund = await getFundOption()
fundOption.value = resFund.data
const res = await getSubCompOpt()
companyOption.value = res.data
}
const changeName = (option, value) => {
let name = ''
option.forEach(item => {
if (item.value == value) {
name = item.label
}
})
return name
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watchEffect(() => {
return Object.keys(props.formData).length && (localFormData.value = props.formData)
})
getFundOptions()
</script>
<style scoped>
.detail-block {
overflow-x: hidden;
overflow-y: auto;
padding-bottom: 20px;
}
</style>

View File

@@ -0,0 +1,15 @@
import request from '@/utils/request'
export const getBaseInfoApi = (projectId) => {
return request({
url: '/workflow/details/info/'+projectId,
method: 'get',
})
}
export const getMapProjectStateInfo = (projectId, state) => {
return request({
url: `/workflow/details/${projectId}/${state}`,
method: 'get'
})
}

View File

@@ -0,0 +1,170 @@
<template>
<StepsMoblie :active="route.query.id==='-1'?currentStep-1:currentStep" @setDetail="setDetail" @stepChange="stepChange"
:reportType="route.query.id==='-1'?'direct':''">
<template #content>
<collection-detail :formData="detailData.formData"
:data="detailData"
:processViewer="commonProvessViewer"
v-show="showActive == '00'"
:fileListShow="fileListShow"
v-model:value="auditOpinion"
/>
<summary-detail v-show="showActive == '10'"
:formData="detailData.formData"
:data="detailData"
:processViewer="commonProvessViewer"
:fileListShow="fileListShow"
v-model:value="auditOpinion"/>
<ApprovalDetail type="approval"
v-if="showActive == '20'&&!editShow"
:formData="detailData.formData"
:data="detailData"
:processViewer="commonProvessViewer"
:fileListShow="fileListShow"
v-model:value="auditOpinion"/>
<ApprovalDetail type="execute"
v-if="showActive == '40'&&!editShow"
:formData="detailData.formData"
:data="detailData"
:processViewer="commonProvessViewer"
:fileListShow="fileListShow"
v-model:value="auditOpinion"/>
<ApprovalDetail type="archivist"
v-show="showActive == '50'&&!editShow"
:formData="detailData.formData"
:data="detailData"
:processViewer="commonProvessViewer"
:fileListShow="fileListShow"
v-model:value="auditOpinion"/>
<ProjectApply :title="applyTitle"
v-if="editShow"
:mode="mode"
:step="showActive"
:data="detailData"
:formData="detailData.formData"/>
</template>
</StepsMoblie>
<div style="width: 100%;height: 30px"></div>
<Opinion v-if="detailData.taskId" :formData="detailData.formData" :taskId="detailData.taskId"
v-model:value="auditOpinion"/>
</template>
<script setup lang="jsx">
import {useProcessStore} from '@/stores/processStore.js';
import {ElLoading, ElNotification} from "element-plus";
import ApprovalDetail from './ApprovalDetailMoblie.vue';
import CollectionDetail from './CollectionDetailMoblie.vue';
import SummaryDetail from './SummaryDetailMoblie.vue';
import Opinion from './OpinionMoblie.vue';
import StepsMoblie from './StepsMoblie.vue';
import ProjectApply from './ProjectApplyMoblie.vue';
const route = useRoute()
const editShow = ref(false)
const applyTitle = ref('apply')
const loading = ref(false)
const processStore = useProcessStore()
const fileListShow = ref('READ')
const mode = ref('')
const currentStep = ref()
const auditOpinion = ref('')
// const step = ref(route.query.step)
route.query.step == '10' && (currentStep.value = 1)
route.query.step == '20' && (currentStep.value = 2)
route.query.step == '40' && (currentStep.value = 3)
route.query.step == '50' && (currentStep.value = 4)
const showActive = ref()
const detailData = ref({})
const commonProvessViewer = ref(true)
const getAllInfo = async (state) => {
const loading = ElLoading.service({fullscreen: true})
try {
fileListShow.value = 'READ'
commonProvessViewer.value = false
const {data, code, msg} = await getMapProjectStateInfo(route.query.projectId, state)
if (code === 1000) {
data.formData.preProcess = data.formData.preProcess ? JSON.parse(data.formData.preProcess) : undefined
detailData.value = data
mode.value = data.formData.mode
processStore.setDesign(data)
processStore.runningList.value = data.runningList;
processStore.endList.value = data.endList;
processStore.noTakeList.value = data.noTakeList;
processStore.refuseList.value = data.refuseList;
processStore.passList.value = data.passList;
nextTick(() => {
commonProvessViewer.value = true
if (data.formPermMap && data.formPermMap["fileList"]) {
fileListShow.value = data.formPermMap["fileList"].perm
}
})
changeModel(state, mode.value)
loading.close()
} else {
ElNotification({
title: '提示',
message: msg,
type: 'error'
})
if (msg === '查询结果为空') {
detailData.value = []
detailData.value.formData = {}
}
loading.close()
}
} catch {
loading.close()
}
}
const changeModel = (active, mode) => {
editShow.value = false
nextTick(() => {
editShow.value = mode === 'submit' || mode === 'resubmit';
if (route.query.step === '20' && active === '20') {
applyTitle.value = 'apply'
} else if (route.query.step === '40' && active === '40') {
applyTitle.value = 'check'
} else if (route.query.step === '50' && active === '50') {
applyTitle.value = 'filing'
}
})
}
const setDetail = (active) => {
showActive.value = active
getAllInfo(active)
}
const stepChange = (data) => {
showActive.value = data.active
getAllInfo(data.active)
}
</script>
<style scoped lang="scss">
.detail-block {
padding-top: 15px;
}
:deep(.el-tabs__nav-scroll) {
width: 100%;
display: flex;
.el-tabs__nav {
display: flex;
flex: 1;
.el-tabs__item {
flex: 1;
font-size: 16px;
}
//.is-active {
// color: black;
// //background-color: #DED0B2;
//}
}
}
</style>

View File

@@ -27,8 +27,8 @@
</template>
</fvTable>
<div class="approval-record">
<div style="display: flex;align-items: center;margin-bottom: 20px">
<baseTitle title="流程图"></baseTitle>
<div style="display: flex;align-items: center;justify-content: flex-end;">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color: #13ce66; --el-switch-off-color:#BEA266;margin-left: 10px"
@@ -46,7 +46,7 @@
<script setup lang="jsx">
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
import {ElMessageBox, ElNotification} from "element-plus";
import {ElNotification} from "element-plus";
import {addFund, resubmitFund, getFundDetail, getFundProcess} from "@/api/special-fund";
import {useRouter} from "vue-router";
import {useTagsView} from '@/stores/tagsview.js'
@@ -155,7 +155,7 @@ const compositeParam = (item) => {
}
}
const getFile = (val) => {
console.log('上传文件', val)
// console.log('上传文件', val)
showTable.value = false
let fileObj = compositeParam(val)
formData.value.files.push(fileObj)

View File

@@ -42,7 +42,8 @@ const searchConfig = reactive([
clearable: true,
placeholder: '请输入资金金额查询'
}
}, {
},
{
label: '剩余金额(元)',
prop: 'residualAmount',
component: 'el-input',
@@ -50,7 +51,8 @@ const searchConfig = reactive([
clearable: true,
placeholder: '请输入剩余金额查询'
}
}, {
},
{
label: '项目数量',
prop: 'projectNumber',
component: 'el-input',

View File

@@ -8,10 +8,10 @@
import { onMounted } from 'vue';
onMounted(()=>{
console.log('步骤一挂载');
// console.log('步骤一挂载');
})
</script>
<style lang="scss" scoped>
</style>
</style>

View File

@@ -8,10 +8,10 @@
import { onMounted } from 'vue';
onMounted(()=>{
console.log('步骤一挂载');
// console.log('步骤一挂载');
})
</script>
<style lang="scss" scoped>
</style>
</style>

View File

@@ -8,10 +8,10 @@
import { onMounted } from 'vue';
onMounted(()=>{
console.log('步骤一挂载');
// console.log('步骤一挂载');
})
</script>
<style lang="scss" scoped>
</style>
</style>

View File

@@ -8,10 +8,10 @@
import { onMounted } from 'vue';
onMounted(()=>{
console.log('步骤一挂载');
// console.log('步骤一挂载');
})
</script>
<style lang="scss" scoped>
</style>
</style>

View File

@@ -8,10 +8,10 @@
import { onMounted } from 'vue';
onMounted(()=>{
console.log('步骤1-5挂载');
// console.log('步骤1-5挂载');
})
</script>
<style lang="scss" scoped>
</style>
</style>

View File

@@ -60,7 +60,7 @@ const schema = reactive([
const getInfo = async () => {
const { data } = await getInfoById(route.query.id)
console.log("🚀 ~ getInfo ~ res:", data)
// console.log("🚀 ~ getInfo ~ res:", data)
const params = {
createTime: data.createTime,
departmentMark: data.departmentMark,
@@ -136,7 +136,7 @@ const setDeptmentInfo = async ({ departmentChargeLeadershipIds = [], departmentH
departmentId: route.query.id
}
const res = await setDeptInfo(params)
console.log(res.data);
// console.log(res.data);
}
getInfo()
@@ -145,4 +145,4 @@ getInfo()
<style lang="scss" scoped>
</style>
</style>

View File

@@ -193,7 +193,7 @@ const getList = async () => {
const getDetail = (deptId) => {
getDeptDetail(deptId).then(res => {
if (res.code === 1000) {
console.log(res.data)
// console.log(res.data)
if (title.value == "行内新增部门") {
form.value.parentId = res.data.deptId
} else {

View File

@@ -38,7 +38,7 @@ import { useTagsView } from '@/stores/tagsview.js'
import { useAuthStore } from '@/stores/userstore.js'
import fvRadio from '@/fvcomponents/fvRadio/index.vue'
import { ElLoading, ElNotification } from 'element-plus';
import { getMenuOpt } from '@/api/system/menuman.js'
import { getMenuOptRole } from '@/api/system/menuman.js'
import { getRoleDetail, operate, getTemRoleOption } from "@/api/role/role";
const tagsViewStore = useTagsView()
@@ -143,8 +143,9 @@ const init = async () => {
form.value.setValues({state: '1', template: false})
const res = await getTemRoleOption()
localData.tempRoleOpt = res.data
const { data } = await getMenuOpt(0)
localData.menuData = data
const { data } = await getMenuOptRole(0)
localData.menuData = data.menuOption
// localData.checked = data.checked
}
const getInfo = async () => {

View File

@@ -191,6 +191,14 @@ const init = async () => {
localData.roleOpt = roleRes.data
const jobRes = await getJobOpt()
localData.jobOpt = jobRes.data
// const reqList = [
// getDeptOpt(),
// getSubCompOpt(),
// getRolesOpt(),
// getJobOpt()
// ]
// const resAll = await Promise.all(reqList)
// console.log("🚀 ~ init ~ resAll:", resAll)
}
const getInfo = async () => {

View File

@@ -114,6 +114,12 @@ const tableConfig = reactive({
label: '手机号码',
align: 'center',
},
{
prop: 'accountType',
label: '主子账号',
align: 'center',
currentRender: ({row, index}) => (<Tag dictType={'account_type'} value={row.accountType} />)
},
{
prop: 'state',
label: '状态',
@@ -154,7 +160,7 @@ const tableConfig = reactive({
})
const init = async () => {
console.log(authStore.roles,'userinfo');
// console.log(authStore.roles,'userinfo');
if(!authStore.roles.includes('superAdmin')) {
searchConfig.value = searchConfig.value.slice(1)
}
@@ -163,7 +169,7 @@ const init = async () => {
searchConfig.value.find(item=>item.prop == 'departmentId').props.data = data
const res = await getSubCompOpt()
searchConfig.value.find(item=>item.prop == 'subCompanyId').props.data = res.data
console.log("🚀 ~ init ~ searchConfig.value:", searchConfig.value)
// console.log("🚀 ~ init ~ searchConfig.value:", searchConfig.value)
}
init()

View File

@@ -7,16 +7,31 @@
:color="operation.color"
size="large"
placement="top">
<el-card>
<div style="display: flex;">
<!-- <avatar-ellipsis :row="3" v-if="operation.userInfo.length > 0" :user-info="operation.userInfo"/>-->
<div>
当前节点: {{ operation.operationName }}
</div>
<div class="card">
<div v-for="(user,index) in operation.userInfo" :key="index" class="avatar_name">
<name-circle :user="user"/>
</div>
<div style="margin-left: 10px;">
<div style="color: #c0bebe">{{ operation.operationName }}</div>
<div style="font-size: 14px; font-weight: bold;">{{ operation.remark }}</div>
<div>
<name-circle :user="user"/>
<span>{{ user.name }}</span>
</div>
<div>
<div class="remark">{{ operation.remark }}</div>
<div>
<div>审批人</div>
<div>{{ user.name }}</div>
</div>
<div v-if="user.auditOpinion">
<div style="margin-bottom: 10px;color: #909399">{{ user.operationTime }}</div>
<div class="username">
<span style="font-weight: bold">审批意见</span>
<el-text v-text="user.auditOpinion" style="word-break: break-all">
</el-text>
</div>
</div>
</div>
</div>
</div>
</el-card>
@@ -32,7 +47,6 @@
<script setup>
import {CircleCheckFilled, Close, Loading, MoreFilled} from "@element-plus/icons-vue";
import AvatarEllipsis from '../process/common/AvatarEllipsis.vue'
import NameCircle from "@/components/NameCircle.vue";
const props = defineProps({
@@ -162,7 +176,7 @@ const initOperationFun = (operation) => {
if (state === 'AGREE' || state === 'AUTO_PASS') {
operation["icon"] = "CircleCheckFilled"
operation["color"] = "#0bbd87"
operation["remark"] = " (已同意)"
operation["remark"] = " 已同意"
}
if (state === 'PASS') {
operation["icon"] = "SemiSelect"
@@ -172,26 +186,26 @@ const initOperationFun = (operation) => {
if (state === 'RUNNING') {
operation["icon"] = "Loading"
operation["color"] = "#f78f5f"
operation["remark"] = " (处理中)"
operation["remark"] = " 处理中"
}
//回退
if (state === 'ROLLBACK') {
operation["icon"] = "RefreshLeft"
operation["color"] = "#f78f5f"
operation["remark"] = " (回退成功)"
operation["remark"] = " 回退成功"
}
//拒绝操作
if (state === 'REFUSE' || state === 'AUTO_REFUSE') {
operation["icon"] = "CircleCloseFilled"
operation["color"] = "#f56c6c"
operation["remark"] = " (拒绝)"
operation["remark"] = " 拒绝"
}
}
//抄送
if (type === 'CC') {
operation["icon"] = "Promotion"
operation["color"] = "#3395f8"
operation["remark"] = " (抄送成功)"
operation["remark"] = " 抄送成功"
}
//评论
if (type === 'COMMENT') {
@@ -199,7 +213,7 @@ const initOperationFun = (operation) => {
if (state === 'COMMENT') {
operation["icon"] = "ChatDotRound"
operation["color"] = "#0bbd87"
operation["remark"] = " (添加了评论)"
operation["remark"] = " 添加了评论"
}
}
//触发器发送http请求
@@ -207,13 +221,13 @@ const initOperationFun = (operation) => {
operation["icon"] = "Share"
if (state === 'SUCCESS') {
operation["color"] = "#0bbd87"
operation["remark"] = " (成功)"
operation["remark"] = " 成功"
} else if (state === 'RUNNING') {
operation["color"] = "#f78f5f"
operation["remark"] = " (请求中)"
operation["remark"] = " 请求中"
} else {
operation["color"] = "#f56c6c"
operation["remark"] = " (失败)"
operation["remark"] = " 失败"
}
}
@@ -222,13 +236,13 @@ const initOperationFun = (operation) => {
operation["icon"] = "Message"
if (state === 'SUCCESS') {
operation["color"] = "#0bbd87"
operation["remark"] = " (成功)"
operation["remark"] = " 成功"
} else if (state === 'RUNNING') {
operation["color"] = "#f78f5f"
operation["remark"] = " (发送中)"
operation["remark"] = " 发送中"
} else {
operation["color"] = "#f78f5f"
operation["remark"] = " (发送中)"
operation["remark"] = " 发送中"
}
}
return operation;
@@ -237,25 +251,84 @@ init()
</script>
<style lang="scss" scoped>
:deep .el-card__body, .el-main {
padding: 10px;
}
.avatar_name {
//width: 45px;
.card {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
margin-right: 5px;
font-size: 15px;
> div:first-child {
display: flex;
}
.avatar_name {
padding: 10px 0;
display: flex;
margin-right: 5px;
border-bottom: 1px solid #ebeef5;
&:last-child {
border-bottom: none;
}
> div:first-child {
display: flex;
> span {
width: 100px;
color: #2a99ff;
margin-left: 10px;
margin-right: 20px;
}
}
> div:nth-child(2) {
display: flex;
flex-direction: column;
color: #8a8a8a;
.remark {
font-weight: bold;
}
> div {
margin-bottom: 5px;
}
> div:nth-child(2) {
display: flex;
margin-top: -5px;
}
}
}
}
.el-timeline-item__node {
position: absolute;
bottom: 20px;
right: 1px;
}
.username {
//width: 90px;
margin-top: 10px;
background: #f5f5f5;
padding: 12px;
//overflow: hidden;
//.el-tooltip__trigger {
// width: 90px;
// text-align: center;
// //padding-top: 2px;
// //text-align: center;
// text-overflow: ellipsis;
// white-space: nowrap;
// overflow: hidden
//}
}
</style>

View File

@@ -66,7 +66,7 @@ const _value = computed({
return props.value;
},
set(val) {
console.log(val,"组件")
// console.log(val,"组件")
emit("update:value", val);
}
})
@@ -76,7 +76,7 @@ const chinese = computed(()=>{
})
const convertCurrency = (money) => {
console.log("zhuanhuan ",money)
// console.log("zhuanhuan ",money)
//汉字的数字
const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
//基本单位

View File

@@ -187,7 +187,7 @@ const getMinWidth = (col) => {
}
}
const showError = (col, val) => {
console.log('showError', val)
// console.log('showError', val)
if (col.props.required) {
switch (col.valueType) {
case ValueType.dept:
@@ -208,7 +208,7 @@ const delRow = (i) => {
_value.value.splice(i, 1)
}
const addRow = () => {
console.log('添加', props.maxSize, _value.value)
// console.log('添加', props.maxSize, _value.value)
if (props.maxSize > 0 && _value.value.length >= props.maxSize) {
console.log('限制大小')
ElMessage.warning(`最多只能添加${props.maxSize}`)

View File

@@ -79,7 +79,7 @@ const chooseUser=()=>{
userPicker.value.showUserPicker()
}
watch(() => props.perm, (newVal, oldVal) => {
console.log('newVal',newVal,userPicker.value)
// console.log('newVal',newVal,userPicker.value)
});
const selected = (select) => {
@@ -93,7 +93,7 @@ const selected = (select) => {
userInfoList.push(userInfo)
}
userList.value = userInfoList
console.log('select',userList.value)
// console.log('select',userList.value)
}
const delDept = (i) => {
userList.value.splice(i, 1)

View File

@@ -38,7 +38,7 @@ export default {
}
},
created() {
console.log("出发了",this.value.placeholder,!this.value.placeholder)
// console.log("出发了",this.value.placeholder,!this.value.placeholder)
if (undefined !== this.value.placeholder){
this.placeholder = this.value.placeholder
}else {

View File

@@ -1,118 +1,119 @@
//审批节点默认属性
export const APPROVAL_PROPS = {
assignedType: "ASSIGN_USER", //审批类型
mode: "AND", //会签模式
sign: false, //是否签字
headerBgc: '#ff943e', //节点背景颜色
nobody: { //没有审批的的时候需要的操作
handler: "TO_PASS", //操作
assignedUser: [] //审批人列表
assignedType: "ASSIGN_USER", //审批类型
mode: "AND", //会签模式
sign: false, //是否签字
headerBgc: '#ff943e', //节点背景颜色
nobody: { //没有审批的的时候需要的操作
handler: "TO_PASS", //操作
assignedUser: [] //审批人列表
},
matrixApproval: true,
timeLimit: { //边界事件
timeout: { //超时提醒时间
unit: "H",
value: 0
},
timeLimit: { //边界事件
timeout: { //超时提醒时间
unit: "H",
value: 0
},
handler: { //超时提醒触发时候的操作
type: "REFUSE", //操作
notify: {
once: true, //是否循环
hour: 1
}
}
},
assignedUser: [], // 审批人列表
formPerms: [], //表单权限
selfSelect: { //用户自选
multiple: false //用户自选时是否是多选
},
leaderTop: { //领导
endCondition: "TOP",
endLevel: 1,
},
leader: { //第几级领导
level: 1
},
listener:{
state: false,
list:[]
},
roleList: [], //角色列
refuse: { //拒绝的操作
type: 'TO_END', //驳回规则 TO_END TO_NODE TO_BEFORE
target: '' //驳回到指定ID的节点
},
formUser: '' //表单用户
handler: { //超时提醒触发时候的操作
type: "REFUSE", //操作
notify: {
once: true, //是否循环
hour: 1
}
}
},
assignedUser: [], // 审批人列表
formPerms: [], //表单权限
selfSelect: { //用户自选
multiple: false //用户自选时是否是多选
},
leaderTop: { //领导
endCondition: "TOP",
endLevel: 1,
},
leader: { //第几级领导
level: 1
},
listener: {
state: false,
list: []
},
roleList: [], //角色列表
refuse: { //拒绝的操作
type: 'TO_END', //驳回规则 TO_END TO_NODE TO_BEFORE
target: '' //驳回到指定ID的节点
},
formUser: '' //表单用户
}
//根节点默认属性
export const ROOT_PROPS = {
assignedUser: [], //审批人
formPerms: [] //表单权限
assignedUser: [], //审批人
formPerms: [] //表单权限
}
//条件节点默认属性
export const CONDITION_PROPS = {
groupsType: "OR", //条件组逻辑关系 OR、AND
groups: [
{
groupType: "AND", //条件组内条件关系 OR、AND
cids: [], //条件ID集合
conditions: [] //组内子条件
}
],
expression: "" //自定义表达式,灵活构建逻辑关系
groupsType: "OR", //条件组逻辑关系 OR、AND
groups: [
{
groupType: "AND", //条件组内条件关系 OR、AND
cids: [], //条件ID集合
conditions: [] //组内子条件
}
],
expression: "" //自定义表达式,灵活构建逻辑关系
}
//抄送节点默认属性
export const CC_PROPS = {
shouldAdd: false,
assignedUser: [],
formPerms: []
shouldAdd: false,
assignedUser: [],
formPerms: []
}
//触发器节点默认属性
export const TRIGGER_PROPS = {
type: 'WEBHOOK',
http: {
method: 'GET', //请求方法 支持GET/POST
url: '', //URL地址可以直接带参数
headers: [ //http header
{
name: '',
isField: true,
value: '' //支持表达式 ${xxx} xxx为表单字段id
}
],
contentType: 'FORM', //请求参数类型
params: [ //请求参数
{
name: '',
isField: true, //是表单字段还是自定义
value: '' //支持表达式 ${xxx} xxx为表单字段id
}
],
retry: 1,
handlerByScript: false,
success: 'function handlerSuccess(res) {\n return {\n state: true, \n msg: "请求成功!" \n };\n}',
fail: 'function handlerFail(res) {\n return {\n state: true, \n msg: "请求失败!" \n };\n}'
},
email: {
subject: '',
to: [],
cc: [],
content: ''
}
type: 'WEBHOOK',
http: {
method: 'GET', //请求方法 支持GET/POST
url: '', //URL地址可以直接带参数
headers: [ //http header
{
name: '',
isField: true,
value: '' //支持表达式 ${xxx} xxx为表单字段id
}
],
contentType: 'FORM', //请求参数类型
params: [ //请求参数
{
name: '',
isField: true, //是表单字段还是自定义
value: '' //支持表达式 ${xxx} xxx为表单字段id
}
],
retry: 1,
handlerByScript: false,
success: 'function handlerSuccess(res) {\n return {\n state: true, \n msg: "请求成功!" \n };\n}',
fail: 'function handlerFail(res) {\n return {\n state: true, \n msg: "请求失败!" \n };\n}'
},
email: {
subject: '',
to: [],
cc: [],
content: ''
}
}
//延时节点默认属性
export const DELAY_PROPS = {
type: "FIXED", //延时类型 FIXED:到达当前节点后延时固定时长 、AUTO:延时到 dateTime设置的时间
time: 0, //延时时间
unit: "M", //时间单位 D天 H小时 M分钟
dateTime: "" //如果当天没有超过设置的此时间点,就延时到这个指定的时间,到了就直接跳过不延时
type: "FIXED", //延时类型 FIXED:到达当前节点后延时固定时长 、AUTO:延时到 dateTime设置的时间
time: 0, //延时时间
unit: "M", //时间单位 D天 H小时 M分钟
dateTime: "" //如果当天没有超过设置的此时间点,就延时到这个指定的时间,到了就直接跳过不延时
}
export default {
APPROVAL_PROPS, CC_PROPS, DELAY_PROPS, CONDITION_PROPS, ROOT_PROPS, TRIGGER_PROPS
APPROVAL_PROPS, CC_PROPS, DELAY_PROPS, CONDITION_PROPS, ROOT_PROPS, TRIGGER_PROPS
}

View File

@@ -57,7 +57,7 @@ import ProcessSetting from "./ProcessSetting.vue";
import Ellipsis from '@/views/workflow/process/common/Ellipsis.vue'
import {getCurrentInstance} from '@vue/runtime-core';
import {useTagsView} from '@/stores/tagsview.js'
import {ElMessageBox,ElNotification} from "element-plus";
import {ElMessageBox, ElNotification} from "element-plus";
const tagsViewStore = useTagsView()
@@ -87,7 +87,7 @@ const validOptions = ref([
{title: '审批流程', description: '', icon: '', status: ''},
// {title: '扩展设置', description: '', icon: '', status: ''}
])
onActivated(()=>{
onActivated(() => {
activeSelect.value = 'processSetting'
init()
})
@@ -157,27 +157,31 @@ const loadInitFrom = () => {
type: "END",
}
],
processFromPerms: [{
id: "projectName",
title: "项目名称",
required: true,
perm: "R"
}, {
id: "projectType",
title: "项目类型",
required: true,
perm: "R"
}, {
id: "projectDesc",
title: "项目描述",
required: true,
perm: "R"
}, {
id: "projectManager",
title: "项目经理",
required: true,
perm: "R"
}],
processFromPerms: [
{
id: "projectName",
title: "项目名称",
required: true,
perm: "R"
},
{
id: "projectType",
title: "项目类型",
required: true,
perm: "R"
},
{
id: "projectDesc",
title: "项目描述",
required: true,
perm: "R"
},
{
id: "projectManager",
title: "项目经理",
required: true,
perm: "R"
}],
remark: "备注说明"
}
processStore.setDesign(design)
@@ -187,17 +191,6 @@ const loadInitFrom = () => {
})
}
const getRandomId = () => {
let d = new Date().getTime()
// x 是 0-9 或 a-f 范围内的一个32位十六进制数
let id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = (d + Math.random() * 16) % 16 | 0
d = Math.floor(d / 16)
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
})
return id
}
const getProcessInfo = async () => {
getProcessDefinitionInfo(params.deploymentId).then(res => {
ElNotification({
@@ -252,7 +245,7 @@ const getDefaultValidErr = () => {
}
}
const showValidFinish = (success, err) => {
console.log("处理完成")
// console.log("处理完成")
validResult.value.success = success
validResult.value.finished = true
validResult.value.title = success ? '校验完成 😀' : '校验失败 '
@@ -312,11 +305,11 @@ const doPublish = () => {
type: 'warning'
}).then(() => {
let design = processStore.getDesign()
console.log(design)
// console.log(design)
let template = {
...design
}
console.log(template)
// console.log(template)
addProcessDefinition(template).then(res => {
ElNotification({
title: '提示',
@@ -332,7 +325,7 @@ const doPublish = () => {
ElNotification({
title: '提示',
message: err,
type:'error'
type: 'error'
})
})
})

View File

@@ -402,7 +402,8 @@ const insertConditionsNode = (node) => {
props: deepCopy(DefaultProps.CONDITION_PROPS),
name: "条件1",
children: {}
}, {
},
{
id: getRandomId(),
parentId: node.id,
type: "CONDITION",
@@ -437,7 +438,8 @@ const insertConcurrentsNode = (node) => {
props: deepCopy(DefaultProps.CONDITION_PROPS),
name: "分支1",
children: {}
}, {
},
{
id: getRandomId(),
parentId: node.id,
type: "CONCURRENT",

View File

@@ -7,7 +7,7 @@
<div v-for="(user,index) in userInfo" :key="index" class="avatar_name">
<div class="user">
<div class="circle-user">
<Tooltip :content="user.name" placement="bottom-start" width="45">
<Tooltip :content="user.name" placement="bottom-start" width="45px">
</Tooltip>
</div>
<div v-if="user.icon && mode === 'preview'"

View File

@@ -99,7 +99,7 @@ const getDepartmentTreeList = () => {
//获取部门信息
getDepartmentTree().then(res => {
deptList.value = res.data;
console.log("获取部门信息===========", res.data);
// console.log("获取部门信息===========", res.data);
});
};
const filterNode = (value, data) => {

View File

@@ -5,7 +5,7 @@
<div class="picker">
<div class="candidate" v-loading="loading">
<el-input v-model="filterText" @change="getList(1)"
clearable placeholder="输入部门/昵称进行搜索">
clearable placeholder="输入昵称进行搜索">
<template #append>
<el-button @click="getList(1)">搜索</el-button>
</template>
@@ -20,7 +20,7 @@
<template #default="{ node, data }">
<div class="tree-node">
<div v-if="data.type === 0" style="display: flex;align-items: center;padding: 3px 0">
<el-icon>
<el-icon :color="data.accountType==='0'?'#95d475':'#409eff'">
<UserFilled/>
</el-icon>
{{ node.label }}-{{ data.companyName }}
@@ -51,6 +51,9 @@
<div class="org-items">
<el-empty :image-size="100" description="请点击左侧列表选择数据" v-show="selectList.length === 0"/>
<div v-for="(selectItem, selectIndex) in selectList" :key="selectIndex" class="org-item">
<el-icon :color="selectItem.accountType==='0'?'#95d475':'#409eff'" size="20">
<UserFilled/>
</el-icon>
{{ selectItem.name }}-{{ selectItem.companyName }}
<el-icon @click="noSelected(selectItem)" size="20" style="margin-left: 10px;cursor: pointer;">
<CircleClose/>
@@ -67,9 +70,8 @@
</template>
<script setup>
import {computed, defineProps, defineExpose} from "vue";
import {ElMessageBox} from "element-plus";
import {getMosrDept} from "@/api/workflow/process-user";
import {getMosrUser} from "@/api/workflow/process-user";
const props = defineProps({
value: {
@@ -85,6 +87,11 @@ const props = defineProps({
showCheckbox: { //是否显示左侧选择框
default: true,
type: Boolean
},
//打开弹窗时是否重置选中数据
setNullToSelectList: {
default: false,
type: Boolean
}
});
const radio = ref(0);
@@ -125,7 +132,6 @@ const _value = computed({
});
watch(() => filterText.value, (newVal) => {
console.log('filterText.value', newVal)
filterText.value = newVal
});
@@ -148,8 +154,7 @@ const getList = (flag) => {
chooseName: filterText.value
}
}
getMosrDept(params).then(res => {
console.log('selectItem.type', selectItem.type)
getMosrUser(params).then(res => {
// if (res.data) {
if (selectItem.type === -1) {
dataList.value = res.data;
@@ -187,11 +192,14 @@ const showUserPicker = () => {
value: "0"
};
dataList.value = [];
// selectList.value = []
if(props.setNullToSelectList){
selectList.value = []
}
chooseId.value = 0;
radio.value = 0;
visible.value = true;
expandedKeys.value = [];
filterText.value = ''
getList();
};
const handleChange = (item, data) => {

View File

@@ -273,7 +273,6 @@ const props = defineProps({
const nodeProps = computed(() => {
processStore.getSelectedNode().props.matrixApproval=true
return processStore.getSelectedNode().props;
})

View File

@@ -194,7 +194,7 @@ const selectUser = (value, orgType) => {
}
const filterConditionMosr = (list) => {
processFromPerms.value.forEach((item) => {
console.log(item)
// console.log(item)
if (item.required && supportTypes.value.indexOf(item.valueType) > -1){
list.push({title: item.title, id: item.id, valueType: item.valueType})
}

View File

@@ -315,7 +315,7 @@ const requestTestHandler = () => {
default:
break;
}
console.log("==================[测试打印内容]==================")
// console.log("==================[测试打印内容]==================")
request.then(res => {
console.log(res)
if (res.status === 200) {

View File

@@ -188,7 +188,6 @@ const viewHistoricalVersion = (row) => {
loading.value = true
getHistoryVersion(row.processDefinitionKey).then(res => {
loading.value = false;
// console.log("历史版本数据==", res.data);
res.data.forEach(row => {
row.logo = JSON.parse(row.logo);
});

View File

@@ -103,7 +103,6 @@ const content = computed(() => {
//校验数据配置的合法性
const validate = (err) => {
try {
console.log(props.config.props.assignedType)
switch (props.config.props.assignedType) {
case "ASSIGN_USER":
showError.value = !validate_ASSIGN_USER(err);
@@ -113,7 +112,6 @@ const validate = (err) => {
break;
case "SELF_SELECT":
showError.value = !validate_SELF_SELECT(err);
console.log(showError.value);
break;
case "LEADER_TOP":
showError.value = !validate_LEADER_TOP(err);
@@ -139,7 +137,6 @@ const validate = (err) => {
}
return showError
} catch (e) {
console.log(e)
return false;
}
}

View File

@@ -44,7 +44,6 @@ const headerBgc = computed(() => {
const validate = () => {
console.log("调用成功")
return []
}

View File

@@ -81,7 +81,6 @@ const queryForm = ref()
const showDetails = (row, column) => {
if (column.label !== '操作') {
console.log(row)
selectTask.value = row
nextTick(() => {
taskDetails.value.init()