Commit b1cc8a48 by lichengming

添加了委托评审提交审批按钮

parent fe335ba8
/**
* 流程附件
*/
import http from '../http'
export default {
// 查询所有
list: id => http.post('/flow/v1/attachment/list-' + id).then(res => res),
// 删除
delFile: data =>
http.delete('/flow/v1/attachment/?ids=' + data).then(res => res)
}
/**
* 按钮绑定的流程表
*/
import http from '../http'
export default {
// 通过按钮code查询流程
list: data =>
http.post('/flow/v1/buttonFlow/listByButtonCode', data).then(res => res)
}
/**
* 发起流程 -- 新的流程部署
*/
import http from '../http'
import httpJson from '../httpJson'
export default {
// 获取流程的启动表单
renderedStartForm: data =>
http
.get(
'/flow/v1/processInstance/renderedStartForm?processDefinitionId=' + data
)
.then(res => res),
// 启动流程实例
start: data =>
httpJson.post('/flow/v1/processInstance/start', data).then(res => res),
// 查看-流程表单
formData: id =>
http
.get('/flow/v1/processInstance/formData?processInstanceId=' + id)
.then(res => res)
}
/**
* HTTP 请求 axios dto封装
*/
import axios from 'axios'
import global from './config'
import loading from './loading'
// Axios 全局配置
const httpJson = axios.create()
httpJson.defaults.baseURL = global.baseURL
httpJson.defaults.withCredentials = true
// 添加请求拦截器
httpJson.interceptors.request.use(
config => {
if (!global.getLn()) {
window.location.href = global.ssoURL
}
const header = global.headersJson
// 无法获取情况下,设置登录 COOKIE
if (process.__TOKEN__) {
header.Cookie = 'uid=' + process.__TOKEN__
}
config.headers = header
config.transformRequest = global.transformRequestJSON
return config
},
error => {
return Promise.reject(error)
}
)
// 返回数据处理
// 返回格式 {code:业务码 , data: 内容 , msg: 描述}
httpJson.interceptors.response.use(
response => {
console.log('----response---响应结果---', response)
switch (response.data.code) {
case '-2':
global.logout()
window.location.href = global.ssoURL
break
case '1':
return response.data.data
default:
loading.toast.show(response.data.code, response.data.msg)
}
},
error => {
console.log('--error---', error)
if (error.response.status === 401) {
console.log('unauthorized, logging out ...')
}
return Promise.reject(error)
}
)
export default httpJson
...@@ -32,3 +32,6 @@ export { default as soilSample } from './soil/soil-sample' ...@@ -32,3 +32,6 @@ export { default as soilSample } from './soil/soil-sample'
export { default as soilTest } from './soil/soil-test' export { default as soilTest } from './soil/soil-test'
export { default as soilStatistics } from './soil/soil-statistics' export { default as soilStatistics } from './soil/soil-statistics'
export { default as soilReport } from './soil/soil-report' export { default as soilReport } from './soil/soil-report'
export { default as processInstance } from '../api/flow/process-instance'
export { default as flowAttachment } from '../api/flow/attachment'
export { default as buttonFlow } from '../api/flow/button-flow'
<template>
<div>
<div v-if="disabled === undefined || reEdit" class="fl">
<el-upload
:multiple="true"
:action="action"
:show-file-list="false"
:data="dataObj"
:accept="obj.accept"
:on-success="_handleSuccess"
with-credentials
class="upload-file"
list-type="picture-card">
<i slot="default" class="el-icon-plus"></i>
</el-upload>
</div>
<div class="fl">
<ul class="upload-file-ul">
<li v-for="(item,index) in list" :key="index">
<span v-if="!item.url" @click="_edit(item)">{{item.fileName}}</span>
<el-image
v-if="item.url"
:src="item.url"
:preview-src-list="previewList"
style="width: 90px; height: 90px;margin-top:5px">
</el-image>
<div @click="_download(item)" class="upload-list-cover">{{item.fileName}}</div>
<div v-if="disabled === undefined || reEdit" class="upload-list-cover-close">
<i @click="_del(item)" class="el-icon-close" style="margin-left: 10px"/>
</div>
</li>
</ul>
</div>
<div class="clear"></div>
</div>
</template>
<script>
/**
* 流程附件:上传、下载、删除、预览
* 按住ctrl选择多个文件上传
*/
import { flowAttachment } from '../../api'
import global from '../../api/config'
export default {
name: 'UploadFileList',
props: {
// 组件的所有信息
obj: null,
// 是否禁用(表示只读,不许上传)
disabled: null,
// 附件可操作
reEdit: null,
// 流程id(根据流程id查看附件)自定义的
processId: null
},
data() {
return {
dataObj: {
file: ''
},
list: [],
previewList: [],
// 上传附件
action: '',
// 生成form表单的id
createFormKey: '',
flowProcessId: '', // 自己定义的id,用于查询附件
downloadUrl: ''
}
},
watch: {
// 监听processId数据,更新表单
processId: {
handler(val) {
console.log('processId==', val)
if (val) {
this._list()
} else {
this.list = []
}
},
deep: true
},
// 监听obj数据,更新表单
obj: {
handler(val) {
console.log('obj-value==', val)
this._list()
},
deep: true
}
},
mounted() {
this._list()
},
methods: {
// 自己定义的流程id
_replaceId() {
if (this.processId) {
let flowProcessId = ''
const processIdList = this.processId.split(':')
if (processIdList.length === 1) {
flowProcessId = processIdList[0]
} else if (processIdList.length === 3) {
flowProcessId = processIdList[2]
}
this.flowProcessId = flowProcessId
this.action =
global.baseURL + '/flow/v1/attachment/upload-' + flowProcessId
this.downloadUrl = global.baseURL + '/flow/v1/attachment/download?ids='
}
},
_handleSuccess(response, file, fileList) {
// 上传成功
if (response.success) {
this._list()
} else {
this.$message.error(response.msg)
}
},
// list接口
_list: async function() {
this._replaceId()
if (this.flowProcessId) {
const result = await flowAttachment.list(this.flowProcessId)
// 处理数据,可进行预览图片
// 拼接图片预览地址
this.previewList = []
// 支持page与list
const records = result.records ? result.records : result
for (let i = 0; i < records.length; i++) {
// 判断是否是图片格式
if (this.$fileFormat(records[i].type, 'img')) {
const url = this.downloadUrl + records[i].id
this.$set(records[i], 'url', url)
this.previewList.push(url)
}
}
this.list = records
}
},
// 下载
_download(item) {
const url = this.downloadUrl + item.id
window.open(url, '_blank')
},
// 删除
_del(item) {
this.$confirm('确定要删除附件吗?', '提示', {
type: 'warning'
}).then(() => {
this._delOk(item.id)
})
},
_delOk: async function(id) {
const result = await flowAttachment.delFile(id)
if (result) {
this._list()
}
},
// 编辑或预览
_edit(item) {
if (this.disabled === undefined || this.reEdit) {
// 进行编辑
this.$viewDocument(item, 'edit')
} else {
// 进行预览
this.$viewDocument(item, 'readonly')
}
}
}
}
</script>
<style>
/*多个附件上传*/
.upload-file .el-upload--picture-card {
width: 100px;
height: 100px;
line-height: 100px;
}
.upload-file-ul {
overflow: hidden;
}
.upload-file-ul li {
float: left;
text-align: center;
width: 100px;
height: 100px;
line-height: 100px;
border: 1px solid #ddd;
margin-left: 5px;
border-radius: 7px;
position: relative;
}
.upload-list-cover {
display: none;
position: absolute;
left: 0;
right: 0;
top: 70px;
line-height: 30px;
height: 30px;
background: rgba(0, 0, 0, 0.4);
border-bottom-left-radius: 7px;
border-bottom-right-radius: 7px;
}
.upload-file-ul li:hover .upload-list-cover {
display: block;
color: #fff;
cursor: pointer;
}
.upload-list-cover-close {
position: absolute;
z-index: 2000;
left: 70px;
bottom: 70px;
line-height: 30px;
cursor: pointer;
}
.upload-list-cover-close:hover {
color: #eb6877;
}
.upload-file-ul li:hover span {
cursor: pointer;
color: #409eff;
}
/*多个附件上传*/
</style>
<template>
<div>
<el-row :gutter="formConf.gutter">
<el-form
ref="formObj"
:model="formObj"
:label-width="formConf.labelWidth+'px'"
:label-position="formConf.labelPosition"
size="small"
class="form-view-el-form"
>
<el-col
v-for="(item,index) in formList"
:key="index"
:span="item.span"
:class="{'form-border':formConf.formBorder,'form-border-top':formConf.formBorder&&formConf.labelPosition === 'top'}"
>
<!--label-width 首先取组件的宽度,如果组件没有宽度,则取form的宽度-->
<el-form-item
:label="item.showLabel === false ? '' :item.label"
:prop="item.vModel"
:label-width="item.showLabel === false ? '0':(item.labelWidth?item.labelWidth+'px':formConf.labelWidth+'px')"
:class="{'form-p-text':item.tagIcon === 'p-text'}"
:rules="{ required: item.required?item.required:false, message: item.label+'不能为空', trigger: ['blur', 'change'] }"
>
<!--1)单行文本,多行文本,密码-->
<el-input
v-if="item.tagIcon === 'input' ||
item.tagIcon === 'textarea' ||
item.tagIcon === 'password'"
v-model="formObj[item.vModel]"
:type="item.type"
:placeholder="item.placeholder"
:style="item.style"
:autosize="item.autosize"
:maxlength="item.maxlength"
:show-word-limit="item['show-word-limit']"
:show-password="item['show-password']"
:readonly="item.readonly"
:disabled="disabled"
>
<el-button slot="append" v-if="item.append">
{{ item.append }}
</el-button>
</el-input>
<!--2)数字框-->
<el-input-number
v-else-if="item.tagIcon === 'number'"
v-model="formObj[item.vModel]"
:placeholder="item.placeholder"
:style="item.style"
:min="item.min"
:max="item.max"
:step="item.step"
:step-strictly="item['step-strictly']"
:precision="item.precision"
:disabled="disabled"
controls-position="right"
/>
<!--3)下拉选择-->
<el-select
v-else-if="item.tagIcon === 'select'"
v-model="formObj[item.vModel]"
:placeholder="item.placeholder"
:style="item.style"
:clearable="item.clearable"
:filterable="item.filterable"
:multiple="item.multiple"
:allow-create="item['allow-create']"
:disabled="disabled"
default-first-option
>
<el-option
v-for="(itemChild,childIndex) in item.options"
:key="childIndex"
:label="itemChild.label"
:value="itemChild.value"
/>
</el-select>
<!--4)单选框组-->
<el-radio-group
v-else-if="item.tagIcon === 'radio'"
v-model="formObj[item.vModel]"
:placeholder="item.placeholder"
:style="item.style"
:class="{'form-radio-group':item.arrangement === '2'}"
:disabled="disabled"
>
<el-radio
v-for="(itemChild,childIndex) in item.options"
:key="childIndex"
:label="itemChild.value"
>
{{ itemChild.label }}
</el-radio>
</el-radio-group>
<!--5)多选框组 绑定的是数组,默认横向:1,纵向2的时候会添加一个class样式;{@input@} {$remark$}-->
<el-checkbox-group
v-else-if="item.tagIcon === 'checkbox'"
v-model="formObj[item.vModel]"
:placeholder="item.placeholder"
:style="item.style"
:min="item.min"
:max="item.max"
:class="{'form-checkbox-group':item.arrangement === '2'}"
:disabled="disabled"
>
<el-checkbox
v-for="(itemChild,childIndex) in item.options"
:key="childIndex"
:label="itemChild.value"
>
{{ itemChild.label }}
</el-checkbox>
</el-checkbox-group>
<!--6)时间选择-->
<el-time-picker
v-else-if="item.tagIcon === 'time'"
v-model="formObj[item.vModel]"
:placeholder="item.placeholder"
:style="item.style"
:clearable="item.clearable"
:readonly="item.readonly"
:picker-options="item['picker-options']"
:format="item.format"
:value-format="item['value-format']"
:disabled="disabled"
/>
<!--7)日期选择-->
<el-date-picker
v-else-if="item.tagIcon === 'date'"
v-model="formObj[item.vModel]"
:placeholder="item.placeholder"
:style="item.style"
:clearable="item.clearable"
:readonly="item.readonly"
:format="item.format"
:value-format="item['value-format']"
:disabled="disabled"
:type="item.type"
/>
<!--8)文字-->
<div
v-else-if="item.tagIcon === 'p-text'"
:style="{'text-align':item['content-position'],'font-weight':item.fontWeight?'bold':'normal','font-size':item.fontSize}"
style="font-size: 14px"
>
{{ formObj[item.vModel] }}
</div>
<!--9)分隔线-->
<el-divider
v-else-if="item.tagIcon === 'p-divider'"
:content-position="item['content-position']"
>
{{ formObj[item.vModel] }}
</el-divider>
<!--10)超链接-->
<el-link
v-else-if="item.tagIcon === 'p-link'"
:underline="item.underline"
@click.stop="_goto(item)"
>
{{ formObj[item.vModel] }}
</el-link>
<!--11)级联选择-->
<el-cascader
v-else-if="item.tagIcon === 'cascader'"
v-model="formObj[item.vModel]"
:style="item.style"
:clearable="item.clearable"
:filterable="item.filterable"
:props="item.props"
:options="item.options"
:disabled="disabled"
/>
<!--12)开关-->
<el-switch
v-else-if="item.tagIcon === 'switch'"
v-model="formObj[item.vModel]"
:style="item.style"
:active-value="item['active-value']"
:inactive-value="item['inactive-value']"
:disabled="disabled"
/>
<!--13)上传-->
<div v-else-if="item.tagIcon === 'upload'">
<UploadIndex :obj="item" :disabled="disabled" :reEdit="reEdit" :processId="processId"/>
</div>
<!--16)滑块-->
<el-slider
v-else-if="item.tagIcon === 'p-slider'"
v-model="formObj[item.vModel]"
:show-stops="item['show-stops']"
:step="item.step"
:disabled="disabled"
/>
<!--17)评分-->
<el-rate
v-else-if="item.tagIcon === 'rate'"
v-model="formObj[item.vModel]"
:show-text="item['show-text']"
:show-score="item['show-score']"
:disabled="disabled"
/>
<!--18)警告-->
<el-alert
v-else-if="item.tagIcon === 'p-alert'"
:type="item.theme"
:center="item.center"
:title="formObj[item.vModel]"
:description="item.description"
:show-icon="item['show-icon']"
:closable="false"
/>
<!--19)按钮组 为空的,不需要渲染组件-->
<div v-else-if="item.tagIcon === 'p-button-list'"></div>
<!--其他-->
<div v-else style="color:#999">
组件未渲染,请联系管理员
</div>
</el-form-item>
</el-col>
</el-form>
</el-row>
</div>
</template>
<script>
/**
* 表单设计预览公共组件(一个系统只维护一个即可)
* 普通表单设计+流程表单设计 公用一个预览界面
*/
import UploadIndex from '../../../components/base/UploadIndex'
export default {
name: 'DesignFormView',
components: { UploadIndex },
// eslint-disable-next-line vue/require-prop-types
props: ['disabled', 'reEdit', 'processId', 'showOperateBtn'],
data() {
return {
// 表单配置
formConf: {},
// 表单数组
formList: [],
// 表单绑定的数据
formObj: {}
}
},
methods: {
// 初始化表单
_open(data, defaultObj) {
// defaultObj 为填写过的内容
this._initForm(data, defaultObj)
// this.$nextTick(() => {
// this.$refs.formObj.clearValidate()
// })
},
_initForm(data, defaultObj) {
this.formConf = JSON.parse(JSON.stringify(data.formConf))
this.formList = JSON.parse(JSON.stringify(data.list))
for (let i = 0; i < this.formList.length; i++) {
const item = this.formList[i]
// 多选框的默认值是数组类型的、数字类型的没有默认undefined
if (item.tagIcon === 'checkbox' || item.tagIcon === 'number') {
this.$set(this.formObj, item.vModel, item.defaultValue)
} else {
this.$set(
this.formObj,
item.vModel,
item.defaultValue ? item.defaultValue : ''
)
}
// showBtn:true如果发现有按钮组,那么原来的【通过】、【驳回】按钮就会被禁用
if (this.showOperateBtn && item.tagIcon === 'p-button-list') {
this.$emit('find-btn', item)
}
}
// 编辑的时候set上值,回显
if (defaultObj) {
this.formObj = defaultObj
}
},
// 界面跳转
_goto(item) {
if (item.href) {
window.open(item.href, '_blank')
}
}
}
}
</script>
<style>
.form-view-el-form .el-form-item--small.el-form-item {
margin-bottom: 0;
}
.form-view-el-form.el-form--label-top .el-form-item__label {
padding: 0 !important;
}
</style>
<template>
<div>
<el-dialog
v-dialogDrag
:visible.sync="showModal"
title="流程启动表单"
width="1000px"
>
<div>
<DesignFormView ref="form" :processId="processId"/>
</div>
<div slot="footer">
<modal-footer ref="footerModal" :footer="footerList" @on-result-change="_footerResult" />
</div>
</el-dialog>
</div>
</template>
<script>
import { processInstance } from '../../../api'
import DesignFormView from './DesignFormView'
/**
* 流程中配置的启动表单
*/
export default {
name: 'Index',
components: { DesignFormView },
data() {
return {
showModal: false,
processDefinitionId: '',
processId: '', // 临时
footerList: [
{ id: '', name: '取消', type: '' },
{ id: '', name: '发起', type: 'primary' }
]
}
},
methods: {
_open(data, id) {
this.showModal = true
this.processDefinitionId = id
this.processId = id + new Date().getTime()
this._hideLoading()
if (data.renderedStartForm) {
this._initForm(JSON.parse(data.renderedStartForm))
}
},
_initForm(data) {
this.$nextTick(() => {
this.$refs.form._open(data)
})
},
// modal
_footerResult(name) {
switch (name) {
case '取消':
this.showModal = false
break
case '发起':
this._ok()
break
}
},
_hideLoading() {
this.$refs.footerModal._hideLoading()
},
_ok: async function() {
const obj = {
processDefinitionId: this.processDefinitionId,
values: {}
}
// 填写的表单数据
const formObj = this.$refs.form.formObj
formObj.processDefinitionId = this.processId
obj.values = formObj
// 验证必填项
const formList = this.$refs.form.formList
for (let i = 0; i < formList.length; i++) {
const item = formList[i]
if (item.required && !formObj[item.vModel]) {
this.$message.error(item.label + '不能为空~')
this._hideLoading()
return false
}
}
const result = await processInstance.start(obj)
if (result) {
this.$message.success('发起成功,请到系统管理进行审批')
this.showModal = false
this.$emit('on-result-change')
}
this._hideLoading()
}
}
}
</script>
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
<Operation ref="operation"></Operation> <Operation ref="operation"></Operation>
<EntrustDetail ref="sampleEdit"></EntrustDetail> <EntrustDetail ref="sampleEdit"></EntrustDetail>
<SampleManage ref="sampleManageModal"></SampleManage> <SampleManage ref="sampleManageModal"></SampleManage>
<SelectFlowRelBtn ref="flow"/>
</div> </div>
</template> </template>
<script> <script>
...@@ -61,8 +62,15 @@ import Reason from '../../../components/base/Reason' ...@@ -61,8 +62,15 @@ import Reason from '../../../components/base/Reason'
import SampleManage from '../SoilSampleManage' import SampleManage from '../SoilSampleManage'
import global from '../../../api/config' import global from '../../../api/config'
import EntrustDetail from './EntrustDetail' import EntrustDetail from './EntrustDetail'
import SelectFlowRelBtn from './SelectFlowRelBtn'
export default { export default {
components: { Operation, Reason, EntrustDetail, SampleManage }, components: {
Operation,
Reason,
EntrustDetail,
SampleManage,
SelectFlowRelBtn
},
data() { data() {
return { return {
currentComponent: 'FoodSampleGovern', currentComponent: 'FoodSampleGovern',
...@@ -90,6 +98,11 @@ export default { ...@@ -90,6 +98,11 @@ export default {
type: 'success', type: 'success',
id: '', id: '',
name: '导出标书合同(协议)补充单模板' name: '导出标书合同(协议)补充单模板'
},
{
type: 'success',
id: 'submit-flow',
name: '提交审批'
} }
], ],
iconMsg: [ iconMsg: [
...@@ -159,6 +172,9 @@ export default { ...@@ -159,6 +172,9 @@ export default {
this.currentComponent = componentName this.currentComponent = componentName
this.$nextTick(function() { this.$nextTick(function() {
switch (msg) { switch (msg) {
case '提交审批':
this._submit('submit-flow')
break
case '驳回': case '驳回':
this._goBack() this._goBack()
break break
...@@ -180,6 +196,9 @@ export default { ...@@ -180,6 +196,9 @@ export default {
} }
}) })
}, },
_submit(key) {
this.$refs.flow._open(key)
},
_exportTemplate() { _exportTemplate() {
const data = { const data = {
downloadUrl: downloadUrl:
......
<template>
<div>
<el-dialog
v-drag
:visible.sync="showModal"
:title="modalTitle"
width="500px"
append-to-body
>
<div style="max-height:350px;overflow:auto">
<el-radio-group v-model="selectData" style="display: inline">
<el-radio
:label="item.flowId"
v-for="item in flowList"
:key="item.flowName"
border
style="width:47%;margin-left: 0;margin-right: 10px"
>{{item.flowName}}
</el-radio>
</el-radio-group>
</div>
<div slot="footer">
<ModalFooter ref="footerModal" :footer="footerList" @on-result-change="_footerResult"/>
</div>
</el-dialog>
<!--点击确定后,发起流程-->
<RenderedStartForm ref="startForm" @on-result-change="_close"/>
</div>
</template>
<script>
import ModalFooter from '../../../components/base/modalFooter'
import { processInstance, buttonFlow } from '../../../api'
import RenderedStartForm from './RenderedStartForm'
/**
* 根据按钮code选择流程
*/
export default {
name: 'SelectFlowByBtn',
components: { ModalFooter, RenderedStartForm },
data() {
return {
showModal: false,
modalTitle: '请选择流程',
getPage: {},
// 选中的数据
selectData: '',
flowList: [],
footerList: [
{ id: '', name: '取消', type: '' },
{ id: '', name: '确定', type: 'primary' }
],
// 按钮的code
btnCode: ''
}
},
methods: {
_open(btnCode) {
this.$nextTick(() => {
this.btnCode = btnCode
this.selectData = ''
this._hideLoading()
this._getFlowByBtn()
})
},
// 根据按钮code查询流程列表
_getFlowByBtn: async function() {
const result = await buttonFlow.list({ buttonCode: this.btnCode })
this.flowList = result
if (result && result.length > 1) {
// 超过一个需要进行选择
this.showModal = true
} else if (result && result.length === 1) {
// 一个则直接调用接口
this.selectData = result[0].flowId
this._startForm()
} else {
this.$message.warning('按钮暂无绑定流程,无法发起流程!')
}
},
/** *modal-footer */
_footerResult(name) {
switch (name) {
case '取消':
this.showModal = false
break
case '确定':
if (this.selectData !== '') {
this._startForm()
} else {
this.$message.warning('请选择一个流程!')
this._hideLoading()
}
break
}
},
_hideLoading() {
this.$refs.footerModal._hideLoading()
},
// 发起流程 ----->1.有表单需要填写表单数据局;2.无表单直接发起
// 启动流程表单
_startForm: async function() {
const result = await processInstance.renderedStartForm(this.selectData)
if (result && result.renderedStartForm !== '') {
// 表单信息不为空,才弹出表单界面
this.$refs.startForm._open(result, this.selectData)
} else {
this._startOk()
}
},
_startOk: async function() {
const obj = {
processDefinitionId: this.selectData
}
const result = await processInstance.start(obj)
if (result) {
this.$message.success('发起成功,请到系统管理进行审批')
}
this._hideLoading()
},
_close() {
this.showModal = false
}
}
}
</script>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment