添加流程管理页面包括三部分
引入api代码
引入主页面代码
添加菜单
引入api代码(fp放在api目录下)
- exam.js
import request from '@/utils/request'
// 查询流程节点与审批关联列表
export function listExam(query) {
return request({
url: '/fp/exam/list',
method: 'get',
params: query
})
}
// 查询流程节点与审批关联详细
export function getExam(nodeId) {
return request({
url: '/fp/exam/' + nodeId,
method: 'get'
})
}
// 新增流程节点与审批关联
export function addExam(data) {
return request({
url: '/fp/exam',
method: 'post',
data: data
})
}
// 修改流程节点与审批关联
export function updateExam(data) {
return request({
url: '/fp/exam',
method: 'put',
data: data
})
}
// 删除流程节点与审批关联
export function delExam(nodeId) {
return request({
url: '/fp/exam/' + nodeId,
method: 'delete'
})
}
// 导出流程节点与审批关联
export function exportExam(query) {
return request({
url: '/fp/exam/export',
method: 'get',
params: query
})
}
- group.js
import request from '@/utils/request'
// 查询流程分组列表
export function listGroup(query) {
return request({
url: '/transmonitor/group/list',
method: 'get',
params: query
})
}
// 查询流程分组列表不分页
export function allGroup(query) {
return request({
url: '/fp/group/all',
method: 'get',
params: query
})
}
// 查询流程分组详细
export function getGroup(id) {
return request({
url: '/fp/group/' + id,
method: 'get'
})
}
// 新增流程分组
export function addGroup(data) {
return request({
url: '/fp/group',
method: 'post',
data: data
})
}
// 分组排序
export function sortGroup(data) {
return request({
url: '/fp/group/sort',
method: 'post',
data: data
})
}
// 修改流程分组
export function updateGroup(data) {
return request({
url: '/fp/group',
method: 'put',
data: data
})
}
// 删除流程分组
export function delGroup(id) {
return request({
url: '/fp/group/' + id,
method: 'delete'
})
}
// 导出流程分组
export function exportGroup(query) {
return request({
url: '/fp/group/export',
method: 'get',
params: query
})
}
- mount.js
import request from '@/utils/request'
// 查询流程挂载列表
export function listMount(query) {
return request({
url: '/fp/mount/list',
method: 'get',
params: query
})
}
// 查询流程挂载详细
export function getMount(busCode) {
return request({
url: '/fp/mount/' + busCode,
method: 'get'
})
}
// 新增流程挂载
export function addMount(data) {
return request({
url: '/fp/mount',
method: 'post',
data: data
})
}
// 修改流程挂载
export function updateMount(data) {
return request({
url: '/fp/mount',
method: 'put',
data: data
})
}
// 删除流程挂载
export function delMount(busCode) {
return request({
url: '/fp/mount/' + busCode,
method: 'delete'
})
}
// 导出流程挂载
export function exportMount(query) {
return request({
url: '/fp/mount/export',
method: 'get',
params: query
})
}
- node.js
import request from '@/utils/request'
// 查询流程节点列表
export function listNode(query) {
return request({
url: '/fp/node/list',
method: 'get',
params: query
})
}
// 查询流程回调处理列表 不分页
export function allCallback(query) {
return request({
url: '/fp/callback/all',
method: 'get',
params: query
})
}
// 查询流程进度
export function listPs(query) {
return request({
url: '/fp/busNode/query',
method: 'get',
params: query
})
}
// 查询流程节点详细
export function getNode(nodeId) {
return request({
url: '/fp/node/' + nodeId,
method: 'get'
})
}
// 查询流程节点及操作权限
export function listNodeDatas(proId) {
return request({
url: '/fp/node/datas/' + proId,
method: 'get'
})
}
// 新增流程节点
export function addNode(data) {
return request({
url: '/fp/node',
method: 'post',
data: data
})
}
// 新增流程节点
export function insertNode(data) {
return request({
url: '/fp/node/insert',
method: 'post',
data: data
})
}
// 修改流程节点
export function updateNode(data) {
return request({
url: '/fp/node',
method: 'put',
data: data
})
}
// 删除流程节点
export function delNode(nodeId) {
return request({
url: '/fp/node/' + nodeId,
method: 'delete'
})
}
// 导出流程节点
export function exportNode(query) {
return request({
url: '/fp/node/export',
method: 'get',
params: query
})
}
- proce.js
import request from '@/utils/request'
// 查询流程定义列表
export function listProce(query) {
return request({
url: '/fp/proce/list',
method: 'get',
params: query
})
}
// 查询流程定义列表不分页
export function allProce(query) {
return request({
url: '/fp/proce/all',
method: 'get',
params: query
})
}
// 查询流程定义详细
export function getProce(proId) {
return request({
url: '/fp/proce/' + proId,
method: 'get'
})
}
// 新增流程定义
export function addProce(data) {
return request({
url: '/fp/proce',
method: 'post',
data: data
})
}
// 停用或启用流程
export function setStatus(data) {
return request({
url: '/fp/proce/setStatus',
method: 'post',
data: data
})
}
// 修改流程定义
export function updateProce(data) {
return request({
url: '/fp/proce',
method: 'put',
data: data
})
}
// 删除流程定义
export function delProce(proId) {
return request({
url: '/fp/proce/' + proId,
method: 'delete'
})
}
// 导出流程定义
export function exportProce(query) {
return request({
url: '/fp/proce/export',
method: 'get',
params: query
})
}
// 预览流程节点
export function queryPs(query) {
return request({
url: '/fp/proce/query',
method: 'get',
params: query
})
}
- start.js
import request from '@/utils/request'
// 查询我的申请
export function listApply(query) {
return request({
url: '/fp/start/list',
method: 'get',
params: query
})
}
// 查询抄送我的
export function listCcme(query) {
return request({
url: '/fp/start/ccme',
method: 'get',
params: query
})
}
// 查询由我参与的
export function listBmpt(query) {
return request({
url: '/fp/start/bmpt',
method: 'get',
params: query
})
}
// 查询流程节点列表
export function listStart(query) {
return request({
url: '/fp/start/query',
method: 'get',
params: query
})
}
// 流程节点操作
export function executorFp(data) {
return request({
url: '/fp/start/executorFp',
method: 'post',
data: data
})
}
// 流程启动
export function startFp(data) {
return request({
url: '/fp/start/startFp',
method: 'post',
data: data
})
}
// 流程重新发起
export function initiateFp(data) {
return request({
url: '/fp/start/initiateFp',
method: 'post',
data: data
})
}
// 流程驳回
export function rejectedFp(data) {
return request({
url: '/fp/start/rejectedFp',
method: 'post',
data: data
})
}
引入主页面代码(fp放在views目录下)
- apply–>index.vue
<template>
<div class="app-container">
<div v-if="flag == '1'">
<p style="font-size: 18px; font-weight: bold;">我的申请</p>
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="所属流程" prop="proId">
<el-input
v-model="queryParams.proId"
placeholder="请输入所属流程"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="发起时间" prop="subTime">
<el-input
v-model="queryParams.subTime"
placeholder="请输入发起时间"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="startList" border>
<el-table-column label="流程" align="center" prop="proName">
<template slot-scope="scope">
<el-link :underline="false" type="primary" @click="openFpDesc(scope.row)">{{scope.row.proName}}</el-link>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="proGoStatus">
<template slot-scope="scope">
<el-tag color="#f8eaec" v-if="scope.row.proGoStatus == '5'">已转交</el-tag>
<el-tag type="info" v-if="scope.row.proGoStatus == '4'">已撤回</el-tag>
<el-tag type="danger" v-if="scope.row.proGoStatus == '3'">已驳回</el-tag>
<el-tag type="success" v-if="scope.row.proGoStatus == '2'">已完成</el-tag>
<el-tag type="warning" v-if="scope.row.proGoStatus == '1'">审批中</el-tag>
<el-tag v-if="scope.row.proGoStatus == '0'">未审批</el-tag>
</template>
</el-table-column>
<el-table-column label="待谁处理" align="center">
<template slot-scope="scope">
<span style="color: #CCAD6F;"
v-if="scope.row.todoUserIdDictText">{{scope.row.todoUserIdDictText}}等用户处理中...</span>
<span style="color: #CCAD6F;"
v-if="scope.row.todoRoleIdDictText">{{scope.row.todoRoleIdDictText}}等角色处理中...</span>
<span v-if="!scope.row.todoRoleIdDictText && !scope.row.todoUserIdDictText">流程已结束</span>
</template>
</el-table-column>
<el-table-column label="所属业务类型" align="center" prop="busType">
<template slot-scope="scope">
<el-tag>一般业务</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="110">
<template slot-scope="scope">
<el-button
v-if="scope.row.proGoStatus != '2'"
size="mini"
type="text"
icon="el-icon-refresh-left"
@click="initiateFpStatus(scope.row)"
>撤回
</el-button>
<el-divider v-if="scope.row.proGoStatus != '2'" direction="vertical"></el-divider>
<!-- <el-button
v-if="scope.row.proGoStatus == '2' || scope.row.proGoStatus == '3'"
size="mini"
type="text"
icon="el-icon-thumb"
>重新申请
</el-button>-->
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
<!--审批详情-->
<div v-if="flag == '2'">
<el-row>
<el-col :span="24">
<el-card shadow="never" style="height: 62px;padding-top: 8px;">
<el-row>
<el-col :span="9">
<el-button style="margin-top: -16px;" icon="el-icon-arrow-left" @click="callMainPage">返回</el-button>
</el-col>
<el-col :span="12">
<p style="display: inline;">{{actionRow.groupName}}</p>
</el-col>
<el-col :span="3" style="margin-top: -10px;">
<div style="float: right;margin-right: -4%;">
<el-button style="margin-right: -2%" v-if="!disType"
@click="subForm">提交
</el-button>
<el-button style="margin-right: -2%" type="primary" v-if="actionRow.proGoStatus == '3'"
@click="applyFor">操作
</el-button>
</div>
</el-col>
</el-row>
</el-card>
<el-card shadow="never">
<el-row type="flex">
<el-col :span="20" style="margin-right: 40px;">
<parser :form-conf="formConf"></parser>
</el-col>
<el-col :span="2">
<p style="font-size: 13px;color: #909399;">状态</p>
<el-tag color="#f8eaec" v-if="actionRow.proGoStatus == '5'">已转交</el-tag>
<el-tag type="info" v-if="actionRow.proGoStatus == '4'">已撤回</el-tag>
<el-tag type="danger" v-if="actionRow.proGoStatus == '3'">已驳回</el-tag>
<el-tag type="success" v-if="actionRow.proGoStatus == '2'">已完成</el-tag>
<el-tag type="warning" v-if="actionRow.proGoStatus == '1'">审批中</el-tag>
<el-tag v-if="actionRow.proGoStatus == '0'">未审批</el-tag>
</el-col>
<el-col :span="2">
<p style="font-size: 13px;color: #909399;">提交时间</p>
<p style="font-size: 13px;">{{actionRow.subTime}}</p>
</el-col>
</el-row>
</el-card>
<el-card class="fp-card">
<div slot="header" class="clearfix">
<span>流程进度</span>
</div>
<div class="text item">
<fp-time-line ref="ftl" :activities="activities"></fp-time-line>
</div>
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import Parser from 'form-gen-parser'
import { listApply, initiateFp, rejectedFp } from '@/api/fp/start'
import { listPs } from '@/api/fp/node'
import FpTimeLine from '../model/tl/index'
export default {
name: 'Apply',
components: { Parser, FpTimeLine },
data() {
return {
// 遮罩层
loading: true,
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 是否禁用下拉框
disType: true,
// 总条数
total: 0,
// 流程启动信息表格数据
startList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
proId: null,
subTime: null
},
flag: '1',
actionRow: {},
formConf: {},
activities: [],
selectRow: [],
setForm: { zf: 0 },
taskId: ''
}
},
created() {
this.getList()
},
methods: {
/** 查询流程启动信息列表 */
getList() {
this.loading = true
listApply(this.queryParams).then(response => {
this.startList = response.rows
this.total = response.total
this.loading = false
})
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm')
this.handleQuery()
},
callMainPage() {
this.flag = '1'
this.actionRow = {}
this.activities = []
},
/** 打开审批详情*/
openFpDesc(row) {
this.actionRow = row
//回显数据
this.formData = JSON.parse(row.formData)
this.formConf = JSON.parse(row.formConf)
this.callShowData()
this.flag = '2'
this.queryProcessSchedule()
},
queryProcessSchedule() {
listPs({ startId: this.actionRow.id }).then(res => {
if (res.data) {
this.activities = res.data
}
})
},
callShowData() {
this.formConf.fields.map(item => {
var __config__ = item.__config__
__config__.defaultValue = this.formData[item.__vModel__] ? this.formData[item.__vModel__] : __config__.defaultValue
return item
})
},
initiateFpStatus(scope) {
this.loading = true
const { id, proId } = scope
initiateFp({ id, proId }).then(res => {
this.msgSuccess('操作成功!')
this.getList()
this.loading = false
})
},
applyFor() {
this.disType = !this.disType
},
subForm() {
this.loading = true
rejectedFp({
formData: JSON.stringify(this.formData), ...this.formData.fp,
id: this.actionRow.id
}).then(res => {
this.msgSuccess('操作成功!')
this.callMainPage()
this.loading = false
this.getList()
})
},
}
}
</script>
- bmpt —> index.vue
<template>
<div class="app-container">
<div v-if="flag == '1'">
<p style="font-size: 18px; font-weight: bold;">由我参与</p>
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="所属流程" prop="proId">
<el-input
v-model="queryParams.proId"
placeholder="请输入所属流程"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="发起时间" prop="subTime">
<el-input
v-model="queryParams.subTime"
placeholder="请输入发起时间"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="startList" border>
<el-table-column label="流程" align="center" prop="proName">
<template slot-scope="scope">
<el-link :underline="false" type="primary" @click="openFpDesc(scope.row)">{{scope.row.proName}}</el-link>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="proGoStatus">
<template slot-scope="scope">
<el-tag color="#f8eaec" v-if="scope.row.proGoStatus == '5'">已转交</el-tag>
<el-tag type="info" v-if="scope.row.proGoStatus == '4'">已撤回</el-tag>
<el-tag type="danger" v-if="scope.row.proGoStatus == '3'">已驳回</el-tag>
<el-tag type="success" v-if="scope.row.proGoStatus == '2'">已完成</el-tag>
<el-tag type="warning" v-if="scope.row.proGoStatus == '1'">审批中</el-tag>
<el-tag v-if="scope.row.proGoStatus == '0'">未审批</el-tag>
</template>
</el-table-column>
<el-table-column label="发起人" align="center" prop="proOriginatorDictText"/>
<el-table-column label="发起时间" align="center" prop="subTime"/>
<el-table-column label="待谁处理" align="center">
<template slot-scope="scope">
<span style="color: #CCAD6F;"
v-if="scope.row.todoUserIdDictText">{{scope.row.todoUserIdDictText}}等用户处理中...</span>
<span style="color: #CCAD6F;"
v-if="scope.row.todoRoleIdDictText">{{scope.row.todoRoleIdDictText}}等角色处理中...</span>
<span v-if="!scope.row.todoRoleIdDictText && !scope.row.todoUserIdDictText">流程已结束</span>
</template>
</el-table-column>
<el-table-column label="所属业务类型" align="center" prop="busType">
<template slot-scope="scope">
<el-tag>一般业务</el-tag>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
<!--审批详情-->
<div v-if="flag == '2'">
<el-row>
<el-col :span="24">
<el-card shadow="never" style="height: 62px;padding-top: 8px;">
<el-row>
<el-col :span="9">
<el-button style="margin-top: -16px;" icon="el-icon-arrow-left" @click="callMainPage">返回</el-button>
</el-col>
<el-col :span="12">
<p style="display: inline;">{{actionRow.groupName}}</p>
</el-col>
<el-col :span="3">
</el-col>
</el-row>
</el-card>
<el-card shadow="never">
<el-row type="flex">
<el-col :span="20" style="margin-right: 40px;">
<parser :form-conf="formConf"></parser>
</el-col>
<el-col :span="2">
<p style="font-size: 13px;color: #909399;">状态</p>
<el-tag color="#f8eaec" v-if="actionRow.proGoStatus == '5'">已转交</el-tag>
<el-tag type="info" v-if="actionRow.proGoStatus == '4'">已撤回</el-tag>
<el-tag type="danger" v-if="actionRow.proGoStatus == '3'">已驳回</el-tag>
<el-tag type="success" v-if="actionRow.proGoStatus == '2'">已完成</el-tag>
<el-tag type="warning" v-if="actionRow.proGoStatus == '1'">审批中</el-tag>
<el-tag v-if="actionRow.proGoStatus == '0'">未审批</el-tag>
</el-col>
<el-col :span="2">
<p style="font-size: 13px;color: #909399;">提交时间</p>
<p style="font-size: 13px;">{{actionRow.subTime}}</p>
</el-col>
</el-row>
</el-card>
<el-card class="fp-card">
<div slot="header" class="clearfix">
<span>流程进度</span>
</div>
<div class="text item">
<fp-time-line ref="ftl" :activities="activities"></fp-time-line>
</div>
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import Parser from 'form-gen-parser'
import { listBmpt } from '@/api/fp/start'
import { listPs } from '@/api/fp/node'
import FpTimeLine from '../model/tl/index'
export default {
name: 'Bmpt',
components: { Parser, FpTimeLine },
data() {
return {
// 遮罩层
loading: true,
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 流程启动信息表格数据
startList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
proId: null,
subTime: null
},
flag: '1',
actionRow: {},
formConf: {},
setForm: { zf: 0 },
activities: [],
selectRow: [],
taskId: ''
}
},
created() {
this.getList()
},
methods: {
/** 查询流程启动信息列表 */
getList() {
this.loading = true
listBmpt(this.queryParams).then(response => {
this.startList = response.rows
this.total = response.total
this.loading = false
})
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm')
this.handleQuery()
},
callMainPage() {
this.flag = '1'
this.actionRow = {}
this.activities = []
},
/** 打开审批详情*/
openFpDesc(row) {
this.actionRow = row
this.formData = JSON.parse(row.formData)
//回显数据
this.formConf = JSON.parse(row.formConf)
this.callShowData()
this.flag = '2'
this.queryProcessSchedule()
},
queryProcessSchedule() {
listPs({ startId: this.actionRow.id }).then(res => {
if (res.data) {
this.activities = res.data
}
})
},
callShowData() {
this.formConf.fields.map(item => {
var __config__ = item.__config__
__config__.defaultValue = this.formData[item.__vModel__] ? this.formData[item.__vModel__] : __config__.defaultValue
return item
})
},
}
}
</script>
- ccme —> index.vue
<template>
<div class="app-container">
<div v-if="flag == '1'">
<p style="font-size: 18px; font-weight: bold;">抄送我的</p>
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="所属流程" prop="proId">
<el-input
v-model="queryParams.proId"
placeholder="请输入所属流程"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="发起时间" prop="subTime">
<el-input
v-model="queryParams.subTime"
placeholder="请输入发起时间"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="startList" border>
<el-table-column label="流程" align="center" prop="proName">
<template slot-scope="scope">
<el-link :underline="false" type="primary" @click="openFpDesc(scope.row)">{{scope.row.proName}}</el-link>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="proGoStatus">
<template slot-scope="scope">
<el-tag color="#f8eaec" v-if="scope.row.proGoStatus == '5'">已转交</el-tag>
<el-tag type="info" v-if="scope.row.proGoStatus == '4'">已撤回</el-tag>
<el-tag type="danger" v-if="scope.row.proGoStatus == '3'">已驳回</el-tag>
<el-tag type="success" v-if="scope.row.proGoStatus == '2'">已完成</el-tag>
<el-tag type="warning" v-if="scope.row.proGoStatus == '1'">审批中</el-tag>
<el-tag v-if="scope.row.proGoStatus == '0'">未审批</el-tag>
</template>
</el-table-column>
<el-table-column label="发起时间" align="center" prop="subTime"/>
<el-table-column label="所属业务类型" align="center" prop="busType">
<template slot-scope="scope">
<el-tag>一般业务</el-tag>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
<!--审批详情-->
<div v-if="flag == '2'">
<el-row>
<el-col :span="24">
<el-card shadow="never" style="height: 62px;padding-top: 8px;">
<el-row>
<el-col :span="9">
<el-button style="margin-top: -16px;" icon="el-icon-arrow-left" @click="callMainPage">返回</el-button>
</el-col>
<el-col :span="12">
<p style="display: inline;line-height: 35px;">{{actionRow.groupName}}</p>
</el-col>
<el-col :span="3">
</el-col>
</el-row>
</el-card>
<el-card shadow="never">
<el-row type="flex">
<el-col :span="20" style="margin-right: 40px;">
<parser :form-conf="formConf"></parser>
</el-col>
<el-col :span="2">
<p style="font-size: 13px;color: #909399;">状态</p>
<el-tag color="#f8eaec" v-if="actionRow.proGoStatus == '5'">已转交</el-tag>
<el-tag type="info" v-if="actionRow.proGoStatus == '4'">已撤回</el-tag>
<el-tag type="danger" v-if="actionRow.proGoStatus == '3'">已驳回</el-tag>
<el-tag type="success" v-if="actionRow.proGoStatus == '2'">已完成</el-tag>
<el-tag type="warning" v-if="actionRow.proGoStatus == '1'">审批中</el-tag>
<el-tag v-if="actionRow.proGoStatus == '0'">未审批</el-tag>
</el-col>
<el-col :span="2">
<p style="font-size: 13px;color: #909399;">提交时间</p>
<p style="font-size: 13px;">{{actionRow.subTime}}</p>
</el-col>
</el-row>
</el-card>
<el-card class="fp-card">
<div slot="header" class="clearfix">
<span>流程进度</span>
</div>
<div class="text item">
<fp-time-line ref="ftl" :activities="activities"></fp-time-line>
</div>
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import Parser from 'form-gen-parser'
import { listCcme } from '@/api/fp/start'
import { listPs } from '@/api/fp/node'
import FpTimeLine from '../model/tl/index'
export default {
name: 'Ccme',
components: { Parser, FpTimeLine },
data() {
return {
// 遮罩层
loading: true,
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 流程启动信息表格数据
startList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
proId: null,
subTime: null
},
flag: '1',
actionRow: {},
formConf: {},
setForm: { zf: 0 },
activities: [],
selectRow: [],
taskId: ''
}
},
created() {
this.getList()
},
methods: {
/** 查询流程启动信息列表 */
getList() {
this.loading = true
listCcme(this.queryParams).then(response => {
this.startList = response.rows
this.total = response.total
this.loading = false
})
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm')
this.handleQuery()
},
callMainPage() {
this.flag = '1'
this.actionRow = {}
this.activities = []
},
/** 打开审批详情*/
openFpDesc(row) {
this.actionRow = row
this.formData = JSON.parse(row.formData)
//回显数据
this.formConf = JSON.parse(row.formConf)
this.callShowData()
this.flag = '2'
this.queryProcessSchedule()
},
queryProcessSchedule() {
listPs({ startId: this.actionRow.id }).then(res => {
if (res.data) {
this.activities = res.data
}
})
},
callShowData() {
this.formConf.fields.map(item => {
var __config__ = item.__config__
__config__.defaultValue = this.formData[item.__vModel__] ? this.formData[item.__vModel__] : __config__.defaultValue
return item
})
}
}
}
</script>
- model —> tl —>index.vue
<template>
<ul class="timeline">
<li class="timeline-item" v-for="(item, index) in activities" :key="item.index">
<div :class="[{ 'item-tail': true, 'item-tail-1': activities[index+1].status == '1',
'item-tail-2': activities[index+1].status == '2', 'item-tail-3': activities[index+1].status == '3',
'item-tail-4': activities[index+1].status == '4', 'item-tail-5': activities[index+1].status == '5', }]"
v-if="index != activities.length - 1"></div>
<div :class="[{'item-node': true, 'item-node-1': item.status == '1' , 'item-node-2': item.status == '2' ,
'item-node-3': item.status == '3' , 'item-node-4': item.status == '4' , 'item-node-5': item.status == '5' }]"></div>
<div class="item-wrapper">
<div class="item-content">{{item.title}}</div>
<div class="item-time" v-if="item.timestamp">时间:{{ item.timestamp }}</div>
<div class="item-approver"> {{item.approver}}</div>
<div v-if="item.remark" class="item-result">理由:
<div :class="[{'item-remark': item.status != '2','item-remark-2': item.status == '2'}]">
{{item.remark}}
</div>
</div>
</div>
<fp-time-line-child v-if="item.pros && item.pros.length > 0" :childs="item.pros"></fp-time-line-child>
</li>
</ul>
</template>
<script>
import FpTimeLineChild from './child'
export default {
name: 'FpTimeLine',
components: { FpTimeLineChild },
props: {
activities: {
default: function(arr) {
return arr
}
}
},
data() {
return {}
}
}
</script>
<style scoped lang='scss'>
.timeline {
margin: 0;
font-size: 18px;
list-style: none;
background-color: #fff;
width: 100%;
height: 100vh;
margin: 20px;
overflow: auto;
.timeline-item {
position: relative;
padding-bottom: 50px;
.item-tail {
position: absolute;
left: 4px;
height: 100%;
border-left: 2px solid #e4e7ed;
}
.item-tail-1 {
border-left: 2px solid #13ce66;
}
.item-tail-2 {
border-left: 2px solid #f56c6c;
}
.item-tail-3 {
border-left: 2px solid #409eff;
}
.item-tail-4 {
border-left: 2px solid pink;
}
.item-tail-5 {
border-left: 2px solid #e6a23c;
}
.item-node {
left: -2px;
width: 15px;
height: 15px;
position: absolute;
background-color: #e4e7ed;
border: 2px solid #ccc;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.item-node-1 {
border: 2px solid #13ce66;
background-color: #13ce66;
}
.item-node-2 {
border: 2px solid #f56c6c;
background-color: #f56c6c;
}
.item-node-3 {
border: 2px solid #409eff;
background-color: #409eff;
}
.item-node-4 {
border: 2px solid pink;
background-color: pink;
}
.item-node-5 {
border: 2px solid #e6a23c;
background-color: #e6a23c;
}
.item-wrapper {
position: relative;
padding-left: 28px;
.item-content {
color: #6395f8;
padding-top: 10px;
}
.item-time {
margin-top: 8px;
color: #909399;
line-height: 1;
font-size: 13px;
}
.item-approver {
color: #909399;
}
.item-remark {
display: inline;
}
.item-remark-2 {
color: red;
display: inline;
}
.item-result {
margin-top: 8px;
}
}
}
}
</style>
- model —> tl —> child.vue
<template>
<div :class="[{'item-top-tail': true, 'item-top-tail-1': childs[0].status == '1',
'item-top-tail-2': childs[0].status == '2', 'item-top-tail-3': childs[0].status == '3',
'item-top-tail-4': childs[0].status == '4', 'item-top-tail-5': childs[0].status == '5' }]">
<ul class="timeline-child">
<li class="timeline-item" v-for="(item, pindex) in childs" :key="pindex">
<div :class="[{'item-tail': true, 'item-tail-1': childs[pindex+1].status == '1',
'item-tail-2': childs[pindex+1].status == '2', 'item-tail-3': childs[pindex+1].status == '3',
'item-tail-4': childs[pindex+1].status == '4', 'item-tail-5': childs[pindex+1].status == '5' }]"
v-if="pindex != childs.length - 1"></div>
<div :class="[{'item-node': true, 'item-node-1': item.status == '1' , 'item-node-2': item.status == '2' ,
'item-node-3': item.status == '3' , 'item-node-4': item.status == '4' , 'item-node-5': item.status == '5' }]"></div>
<div class="item-wrapper">
<div class="item-content">{{item.title}}</div>
<div class="item-time" v-if="item.timestamp">时间:{{ item.timestamp }}</div>
<div class="item-approver"> {{item.approver}}</div>
<div v-if="item.remark" class="item-result">理由:
<div :class="[{'item-remark': item.status != '2','item-remark-2': item.status == '2'}]">
{{item.remark}}</div>
</div>
</div>
<fp-time-line-child v-if="item.pros && item.pros.length > 0" :childs="item.pros"></fp-time-line-child>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'FpTimeLineChild',
props: {
childs: {
default: function(arr) {
return arr
}
}
},
data() {
return {}
}
}
</script>
<style scoped lang='scss'>
.timeline-item {
position: relative;
padding-bottom: 50px;
.item-tail {
position: absolute;
left: 4px;
height: 175px;
border-left: 2px solid #e4e7ed;
}
.item-tail-1 {
border-left: 2px solid #13ce66;
}
.item-tail-2 {
border-left: 2px solid #f56c6c;
}
.item-tail-3 {
border-left: 2px solid #409eff;
}
.item-tail-4 {
border-left: 2px solid pink;
}
.item-tail-5 {
border-left: 2px solid #e6a23c;
}
.item-top-tail {
position: absolute;
left: 13px;
top: 5px;
width: 370px;
height: 100%;
float: left;
border-top: 2px solid #e4e7ed;
.timeline-child {
margin: -6px 60px 0 320px;
font-size: 18px;
list-style: none;
width: 100%;
height: 100%;
}
}
.item-top-tail-1 {
border-top: 2px solid #13ce66;
}
.item-top-tail-2 {
border-top: 2px solid #f56c6c;
}
.item-top-tail-3 {
border-top: 2px solid #409eff;
}
.item-top-tail-4 {
border-top: 2px solid pink;
}
.item-top-tail-5 {
border-top: 2px solid #e6a23c;
}
.item-node {
left: -2px;
width: 15px;
height: 15px;
position: absolute;
background-color: #e4e7ed;
border: 2px solid #ccc;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.item-node-1 {
border: 2px solid #13ce66;
background-color: #13ce66;
}
.item-node-2 {
border: 2px solid #f56c6c;
background-color: #f56c6c;
}
.item-node-3 {
border: 2px solid #409eff;
background-color: #409eff;
}
.item-node-4 {
border: 2px solid pink;
background-color: pink;
}
.item-node-5 {
border: 2px solid #e6a23c;
background-color: #e6a23c;
}
.item-wrapper {
position: relative;
padding-left: 28px;
.item-content {
color: #6395f8;
padding-top: 10px;
}
.item-time {
margin-top: 8px;
color: #909399;
line-height: 1;
font-size: 13px;
}
.item-approver{
color: #909399;
}
.item-remark{
display: inline;
}
.item-remark-2{
color: red;
display: inline;
}
.item-result {
margin-top: 8px;
}
}
}
</style>
- mount —> index.vue
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="挂载流程" prop="proId">
<el-select
v-model="queryParams.proId"
clearable
size="small"
@keyup.enter.native="handleQuery"
placeholder="请选择挂载流程">
<el-option
v-for="dict in proces"
:key="dict.proId"
:label="dict.proName"
:value="dict.proId"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="挂载状态" prop="mountStatus">
<el-select
v-model="queryParams.mountStatus"
clearable
size="small"
@keyup.enter.native="handleQuery"
placeholder="请选择挂载状态">
<el-option
v-for="dict in mountStatuss"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['fp:mount:add']"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['fp:mount:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['fp:mount:remove']"
>删除
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" border :data="mountList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"/>
<el-table-column label="业务唯一编码" align="center" prop="busCode"/>
<el-table-column label="挂载流程" align="center" prop="proId" :formatter="formatFp"/>
<el-table-column label="挂载状态" align="center" prop="mountStatus"
:formatter="(v,c) => dictCodeFormat(v,c,mountStatuss)"/>
<el-table-column label="业务描述" align="center" prop="busDesc"/>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['fp:mount:edit']"
>修改
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['fp:mount:remove']"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改流程挂载对话框 -->
<el-dialog :title="title" :visible.sync="open" width="680px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="160px" class="action-form">
<el-form-item label="业务唯一编码" prop="busCode">
<el-input v-model="form.busCode" :disabled="actionFlag == 'edit'" placeholder="请输入业务唯一编码"/>
</el-form-item>
<el-form-item label="挂载流程" prop="proId">
<el-select
v-model="form.proId"
clearable
size="small"
placeholder="请选择挂载流程">
<el-option
v-for="dict in proces"
:key="dict.proId"
:label="dict.proName"
:value="dict.proId"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="挂载状态" prop="mountStatus">
<el-select
v-model="form.mountStatus"
clearable
size="small"
placeholder="请选择实控人证件类型">
<el-option
v-for="dict in mountStatuss"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="业务描述" prop="busDesc">
<el-input v-model="form.busDesc" placeholder="请输入业务描述"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listMount, getMount, delMount, addMount, updateMount, exportMount } from '@/api/fp/mount'
import { allProce } from '@/api/fp/proce'
export default {
name: 'Mount',
components: {},
data() {
let validateBusCode = async (rule, value, callback) => {
let flag = false
await getMount(value).then(response => {
if(response.data && response.data.busCode)flag = true
})
if (value === '') {
callback(new Error('业务唯一编码不能为空!'))
} else if (flag && this.actionFlag == 'add') {
callback(new Error('该编码已存在,请更换业务唯一编码!'))
} else {
callback()
}
}
return {
// 遮罩层
loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 流程挂载表格数据
mountList: [],
// 弹出层标题
title: '',
actionFlag: '',//操作标识
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
busCode: null,
busDesc: null,
mountStatus: null
},
// 表单参数
form: {},
// 表单校验
rules: {
busCode: [
{ validator: validateBusCode, trigger: 'blur' },
{ required: true, message: '业务唯一编码不能为空!', trigger: 'blur' }
],
proId: [
{ required: true, message: '挂载流程不能为空!', trigger: 'blur' }
],
busDesc: [
{ required: true, message: '业务描述不能为空!', trigger: 'blur' }
],
mountStatus: [
{ required: true, message: '挂载状态不能为空!', trigger: 'blur' }
]
},
mountStatuss: [],//流程挂载状态字典数据
proces: []//流程字典数据
}
},
created() {
this.getList()
this.initDictConfig()
},
methods: {
/**基本字典类型数据初始化*/
initDictConfig() {
this.getDicts('fp_mount_status').then(response => {
this.mountStatuss = response.data
})
allProce({ status: '1' }).then(response => {
this.proces = response.data
})
},
/** 查询流程挂载列表 */
getList() {
this.loading = true
listMount(this.queryParams).then(response => {
this.mountList = response.rows
this.total = response.total
this.loading = false
})
},
// 取消按钮
cancel() {
this.open = false
this.reset()
},
// 表单重置
reset() {
this.form = {
proId: null,
busCode: null,
busDesc: null,
mountStatus: null
}
this.resetForm('form')
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm')
this.handleQuery()
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.busCode)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.actionFlag = 'add'
this.title = '添加流程挂载'
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
this.actionFlag = 'edit'
const busCode = row.busCode || this.ids
getMount(busCode).then(response => {
this.form = response.data
this.open = true
this.title = '修改流程挂载'
})
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate(valid => {
if (valid) {
if (this.actionFlag == 'edit') {
updateMount(this.form).then(response => {
this.msgSuccess('修改成功')
this.open = false
this.getList()
})
} else if (this.actionFlag == 'add') {
addMount(this.form).then(response => {
this.msgSuccess('新增成功')
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const busCodes = row.busCode || this.ids
this.$confirm('是否确认删除流程挂载编号为"' + busCodes + '"的数据项?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(function() {
return delMount(busCodes)
}).then(() => {
this.getList()
this.msgSuccess('删除成功')
}).catch(() => {
})
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams
this.$confirm('是否确认导出所有流程挂载数据项?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.exportLoading = true
return exportMount(queryParams)
}).then(response => {
this.download(response.msg)
this.exportLoading = false
}).catch(() => {
})
},
/** 字典翻译 */
dictCodeFormat(row, column, dictDatas) {
return this.selectDictLabel(dictDatas, eval('row.' + column.property))
},
formatFp(row, column) {
let proName = ''
this.proces.map(item => {
if (item.proId == row.proId) proName = item.proName
})
return proName
}
}
}
</script>
<style scoped lang="scss">
.action-form {
.el-input {
width: 410px
}
.el-textarea {
width: 410px
}
.el-select {
width: 410px;
}
}
.el-dropdown {
font-size: 12px;
.el-dropdown-link {
cursor: pointer;
color: #409EFF;
}
.el-icon-arrow-down {
font-size: 12px;
}
}
</style>
- proce —> fg ----> CodeTypeDialog.vue
<template>
<div>
<el-dialog
v-bind="$attrs"
width="500px"
:close-on-click-modal="false"
:modal-append-to-body="false"
v-on="$listeners"
@open="onOpen"
@close="onClose"
>
<el-row :gutter="15">
<el-form
ref="elForm"
:model="formData"
:rules="rules"
size="medium"
label-width="100px"
>
<el-col :span="24">
<el-form-item label="生成类型" prop="type">
<el-radio-group v-model="formData.type">
<el-radio-button
v-for="(item, index) in typeOptions"
:key="index"
:label="item.value"
:disabled="item.disabled"
>
{{ item.label }}
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="showFileName" label="文件名" prop="fileName">
<el-input v-model="formData.fileName" placeholder="请输入文件名" clearable />
</el-form-item>
</el-col>
</el-form>
</el-row>
<div slot="footer">
<el-button @click="close">
取消
</el-button>
<el-button type="primary" @click="handelConfirm">
确定
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
inheritAttrs: false,
props: ['showFileName'],
data() {
return {
formData: {
fileName: undefined,
type: 'file'
},
rules: {
fileName: [{
required: true,
message: '请输入文件名',
trigger: 'blur'
}],
type: [{
required: true,
message: '生成类型不能为空',
trigger: 'change'
}]
},
typeOptions: [{
label: '页面',
value: 'file'
}, {
label: '弹窗',
value: 'dialog'
}]
}
},
computed: {
},
watch: {},
mounted() {},
methods: {
onOpen() {
if (this.showFileName) {
this.formData.fileName = `${+new Date()}.vue`
}
},
onClose() {
},
close(e) {
this.$emit('update:visible', false)
},
handelConfirm() {
this.$refs.elForm.validate(valid => {
if (!valid) return
this.$emit('confirm', { ...this.formData })
this.close()
})
}
}
}
</script>
<style lang="scss" scoped>
</style>
- proce —> fg —> DraggableItem.vue
<script>
import draggable from 'vuedraggable'
import render from '@/components/render/render'
const components = {
itemBtns(h, currentItem, index, list) {
const { copyItem, deleteItem } = this.$listeners
return [
<span class="drawing-item-copy" title="复制" onClick={event => {
copyItem(currentItem, list); event.stopPropagation()
}}>
<i class="el-icon-copy-document" />
</span>,
<span class="drawing-item-delete" title="删除" onClick={event => {
deleteItem(index, list); event.stopPropagation()
}}>
<i class="el-icon-delete" />
</span>
]
}
}
const layouts = {
colFormItem(h, currentItem, index, list) {
const { activeItem } = this.$listeners
const config = currentItem.__config__
const child = renderChildren.apply(this, arguments)
let className = this.activeId === config.formId ? 'drawing-item active-from-item' : 'drawing-item'
if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
let labelWidth = config.labelWidth ? `${config.labelWidth}px` : null
if (config.showLabel === false) labelWidth = '0'
return (
<el-col span={config.span} class={className}
nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }}>
<el-form-item label-width={labelWidth}
label={config.showLabel ? config.label : ''} required={config.required}>
<render key={config.renderKey} conf={currentItem} onInput={ event => {
this.$set(config, 'defaultValue', event)
}}>
{child}
</render>
</el-form-item>
{components.itemBtns.apply(this, arguments)}
</el-col>
)
},
rowFormItem(h, currentItem, index, list) {
const { activeItem } = this.$listeners
const config = currentItem.__config__
const className = this.activeId === config.formId
? 'drawing-row-item active-from-item'
: 'drawing-row-item'
let child = renderChildren.apply(this, arguments)
if (currentItem.type === 'flex') {
child = <el-row type={currentItem.type} justify={currentItem.justify} align={currentItem.align}>
{child}
</el-row>
}
return (
<el-col span={config.span}>
<el-row gutter={config.gutter} class={className}
nativeOnClick={event => { activeItem(currentItem); event.stopPropagation() }}>
<span class="component-name">{config.componentName}</span>
<draggable list={config.children || []} animation={340}
group="componentsGroup" class="drag-wrapper">
{child}
</draggable>
{components.itemBtns.apply(this, arguments)}
</el-row>
</el-col>
)
},
raw(h, currentItem, index, list) {
const config = currentItem.__config__
const child = renderChildren.apply(this, arguments)
return <render key={config.renderKey} conf={currentItem} onInput={ event => {
this.$set(config, 'defaultValue', event)
}}>
{child}
</render>
}
}
function renderChildren(h, currentItem, index, list) {
const config = currentItem.__config__
if (!Array.isArray(config.children)) return null
return config.children.map((el, i) => {
const layout = layouts[el.__config__.layout]
if (layout) {
return layout.call(this, h, el, i, config.children)
}
return layoutIsNotFound.call(this)
})
}
function layoutIsNotFound() {
throw new Error(`没有与${this.currentItem.__config__.layout}匹配的layout`)
}
export default {
components: {
render,
draggable
},
props: [
'currentItem',
'index',
'drawingList',
'activeId',
'formConf'
],
render(h) {
const layout = layouts[this.currentItem.__config__.layout]
if (layout) {
return layout.call(this, h, this.currentItem, this.index, this.drawingList)
}
return layoutIsNotFound.call(this)
}
}
</script>
- proce —> fg ----> FormDrawer.vue
<template>
<div>
<el-drawer v-bind="$attrs" v-on="$listeners" @opened="onOpen" @close="onClose">
<div style="height:100%">
<el-row style="height:100%;overflow:auto">
<el-col :md="24" :lg="12" class="left-editor">
<div class="setting" title="资源引用" @click="showResource">
<el-badge :is-dot="!!resources.length" class="item">
<i class="el-icon-setting" />
</el-badge>
</div>
<el-tabs v-model="activeTab" type="card" class="editor-tabs">
<el-tab-pane name="html">
<span slot="label">
<i v-if="activeTab==='html'" class="el-icon-edit" />
<i v-else class="el-icon-document" />
template
</span>
</el-tab-pane>
<el-tab-pane name="js">
<span slot="label">
<i v-if="activeTab==='js'" class="el-icon-edit" />
<i v-else class="el-icon-document" />
script
</span>
</el-tab-pane>
<el-tab-pane name="css">
<span slot="label">
<i v-if="activeTab==='css'" class="el-icon-edit" />
<i v-else class="el-icon-document" />
css
</span>
</el-tab-pane>
</el-tabs>
<div v-show="activeTab==='html'" id="editorHtml" class="tab-editor" />
<div v-show="activeTab==='js'" id="editorJs" class="tab-editor" />
<div v-show="activeTab==='css'" id="editorCss" class="tab-editor" />
</el-col>
<el-col :md="24" :lg="12" class="right-preview">
<div class="action-bar" :style="{'text-align': 'left'}">
<span class="bar-btn" @click="runCode">
<i class="el-icon-refresh" />
刷新
</span>
<span class="bar-btn" @click="exportFile">
<i class="el-icon-download" />
导出vue文件
</span>
<span ref="copyBtn" class="bar-btn copy-btn">
<i class="el-icon-document-copy" />
复制代码
</span>
<span class="bar-btn delete-btn" @click="$emit('update:visible', false)">
<i class="el-icon-circle-close" />
关闭
</span>
</div>
<iframe
v-show="isIframeLoaded"
ref="previewPage"
class="result-wrapper"
frameborder="0"
src="preview.html"
@load="iframeLoad"
/>
<div v-show="!isIframeLoaded" v-loading="true" class="result-wrapper" />
</el-col>
</el-row>
</div>
</el-drawer>
<resource-dialog
:visible.sync="resourceVisible"
:origin-resource="resources"
@save="setResource"
/>
</div>
</template>
<script>
import { parse } from '@babel/parser'
import ClipboardJS from 'clipboard'
import { saveAs } from 'file-saver'
import {
makeUpHtml, vueTemplate, vueScript, cssStyle
} from '@/components/generator/html'
import { makeUpJs } from '@/components/generator/js'
import { makeUpCss } from '@/components/generator/css'
import { exportDefault, beautifierConf, titleCase } from '@/utils/index'
import ResourceDialog from './ResourceDialog'
import loadMonaco from '@/utils/loadMonaco'
import loadBeautifier from '@/utils/loadBeautifier'
const editorObj = {
html: null,
js: null,
css: null
}
const mode = {
html: 'html',
js: 'javascript',
css: 'css'
}
let beautifier
let monaco
export default {
components: { ResourceDialog },
props: ['formData', 'generateConf'],
data() {
return {
activeTab: 'html',
htmlCode: '',
jsCode: '',
cssCode: '',
codeFrame: '',
isIframeLoaded: false,
isInitcode: false, // 保证open后两个异步只执行一次runcode
isRefreshCode: false, // 每次打开都需要重新刷新代码
resourceVisible: false,
scripts: [],
links: [],
monaco: null
}
},
computed: {
resources() {
return this.scripts.concat(this.links)
}
},
watch: {},
created() {
},
mounted() {
window.addEventListener('keydown', this.preventDefaultSave)
const clipboard = new ClipboardJS('.copy-btn', {
text: trigger => {
const codeStr = this.generateCode()
this.$notify({
title: '成功',
message: '代码已复制到剪切板,可粘贴。',
type: 'success'
})
return codeStr
}
})
clipboard.on('error', e => {
this.$message.error('代码复制失败')
})
},
beforeDestroy() {
window.removeEventListener('keydown', this.preventDefaultSave)
},
methods: {
preventDefaultSave(e) {
if (e.key === 's' && (e.metaKey || e.ctrlKey)) {
e.preventDefault()
}
},
onOpen() {
const { type } = this.generateConf
this.htmlCode = makeUpHtml(this.formData, type)
this.jsCode = makeUpJs(this.formData, type)
this.cssCode = makeUpCss(this.formData)
loadBeautifier(btf => {
beautifier = btf
this.htmlCode = beautifier.html(this.htmlCode, beautifierConf.html)
this.jsCode = beautifier.js(this.jsCode, beautifierConf.js)
this.cssCode = beautifier.css(this.cssCode, beautifierConf.html)
loadMonaco(val => {
monaco = val
this.setEditorValue('editorHtml', 'html', this.htmlCode)
this.setEditorValue('editorJs', 'js', this.jsCode)
this.setEditorValue('editorCss', 'css', this.cssCode)
if (!this.isInitcode) {
this.isRefreshCode = true
this.isIframeLoaded && (this.isInitcode = true) && this.runCode()
}
})
})
},
onClose() {
this.isInitcode = false
this.isRefreshCode = false
},
iframeLoad() {
if (!this.isInitcode) {
this.isIframeLoaded = true
this.isRefreshCode && (this.isInitcode = true) && this.runCode()
}
},
setEditorValue(id, type, codeStr) {
if (editorObj[type]) {
editorObj[type].setValue(codeStr)
} else {
editorObj[type] = monaco.editor.create(document.getElementById(id), {
value: codeStr,
theme: 'vs-dark',
language: mode[type],
automaticLayout: true
})
}
// ctrl + s 刷新
editorObj[type].onKeyDown(e => {
if (e.keyCode === 49 && (e.metaKey || e.ctrlKey)) {
this.runCode()
}
})
},
runCode() {
const jsCodeStr = editorObj.js.getValue()
try {
const ast = parse(jsCodeStr, { sourceType: 'module' })
const astBody = ast.program.body
if (astBody.length > 1) {
this.$confirm(
'js格式不能识别,仅支持修改export default的对象内容',
'提示',
{
type: 'warning'
}
)
return
}
if (astBody[0].type === 'ExportDefaultDeclaration') {
const postData = {
type: 'refreshFrame',
data: {
generateConf: this.generateConf,
html: editorObj.html.getValue(),
js: jsCodeStr.replace(exportDefault, ''),
css: editorObj.css.getValue(),
scripts: this.scripts,
links: this.links
}
}
this.$refs.previewPage.contentWindow.postMessage(
postData,
location.origin
)
} else {
this.$message.error('请使用export default')
}
} catch (err) {
this.$message.error(`js错误:${err}`)
console.error(err)
}
},
generateCode() {
const html = vueTemplate(editorObj.html.getValue())
const script = vueScript(editorObj.js.getValue())
const css = cssStyle(editorObj.css.getValue())
return beautifier.html(html + script + css, beautifierConf.html)
},
exportFile() {
this.$prompt('文件名:', '导出文件', {
inputValue: `${+new Date()}.vue`,
closeOnClickModal: false,
inputPlaceholder: '请输入文件名'
}).then(({ value }) => {
if (!value) value = `${+new Date()}.vue`
const codeStr = this.generateCode()
const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
saveAs(blob, value)
})
},
showResource() {
this.resourceVisible = true
},
setResource(arr) {
const scripts = []; const
links = []
if (Array.isArray(arr)) {
arr.forEach(item => {
if (item.endsWith('.css')) {
links.push(item)
} else {
scripts.push(item)
}
})
this.scripts = scripts
this.links = links
} else {
this.scripts = []
this.links = []
}
}
}
}
</script>
<style lang="scss" scoped>
@mixin action-bar {
.action-bar {
height: 33px;
background: #f2fafb;
padding: 0 15px;
box-sizing: border-box;
.bar-btn {
display: inline-block;
padding: 0 6px;
line-height: 32px;
color: #8285f5;
cursor: pointer;
font-size: 14px;
user-select: none;
& i {
font-size: 20px;
}
&:hover {
color: #4348d4;
}
}
.bar-btn + .bar-btn {
margin-left: 8px;
}
.delete-btn {
color: #f56c6c;
&:hover {
color: #ea0b30;
}
}
}
}
.tab-editor {
position: absolute;
top: 33px;
bottom: 0;
left: 0;
right: 0;
font-size: 14px;
}
.left-editor {
position: relative;
height: 100%;
background: #1e1e1e;
overflow: hidden;
}
.setting{
position: absolute;
right: 15px;
top: 3px;
color: #a9f122;
font-size: 18px;
cursor: pointer;
z-index: 1;
}
.right-preview {
height: 100%;
.result-wrapper {
height: calc(100vh - 33px);
width: 100%;
overflow: auto;
padding: 12px;
box-sizing: border-box;
}
}
@include action-bar;
::v-deep .el-drawer__header {
display: none;
}
</style>
- proce —> fg ----> IconsDialog.vue
<template>
<div class="icon-dialog">
<el-dialog
v-bind="$attrs"
width="980px"
:modal-append-to-body="false"
v-on="$listeners"
@open="onOpen"
@close="onClose"
>
<div slot="title">
选择图标
<el-input
v-model="key"
size="mini"
:style="{width: '260px'}"
placeholder="请输入图标名称"
prefix-icon="el-icon-search"
clearable
/>
</div>
<ul class="icon-ul">
<li
v-for="icon in iconList"
:key="icon"
:class="active===icon?'active-item':''"
@click="onSelect(icon)"
>
<i :class="icon" />
<div>{{ icon }}</div>
</li>
</ul>
</el-dialog>
</div>
</template>
<script>
import iconList from '@/utils/generator/icon.json'
const originList = iconList.map(name => `el-icon-${name}`)
export default {
inheritAttrs: false,
props: ['current'],
data() {
return {
iconList: originList,
active: null,
key: ''
}
},
watch: {
key(val) {
if (val) {
this.iconList = originList.filter(name => name.indexOf(val) > -1)
} else {
this.iconList = originList
}
}
},
methods: {
onOpen() {
this.active = this.current
this.key = ''
},
onClose() {},
onSelect(icon) {
this.active = icon
this.$emit('select', icon)
this.$emit('update:visible', false)
}
}
}
</script>
<style lang="scss" scoped>
.icon-ul {
margin: 0;
padding: 0;
font-size: 0;
li {
list-style-type: none;
text-align: center;
font-size: 14px;
display: inline-block;
width: 16.66%;
box-sizing: border-box;
height: 108px;
padding: 15px 6px 6px 6px;
cursor: pointer;
overflow: hidden;
&:hover {
background: #f2f2f2;
}
&.active-item{
background: #e1f3fb;
color: #7a6df0
}
> i {
font-size: 30px;
line-height: 50px;
}
}
}
.icon-dialog {
::v-deep .el-dialog {
border-radius: 8px;
margin-bottom: 0;
margin-top: 4vh !important;
display: flex;
flex-direction: column;
max-height: 92vh;
overflow: hidden;
box-sizing: border-box;
.el-dialog__header {
padding-top: 14px;
}
.el-dialog__body {
margin: 0 20px 20px 20px;
padding: 0;
overflow: auto;
}
}
}
</style>
- proce —> fg ----> index.vue
<template>
<div class="container">
<div class="left-board">
<div class="logo-wrapper">
<div class="logo">
基础控件
</div>
</div>
<el-scrollbar class="left-scrollbar">
<div class="components-list">
<div v-for="(item, listIndex) in leftComponents" :key="listIndex">
<div class="components-title">
<svg-icon icon-class="component" />
{{ item.title }}
</div>
<draggable
class="components-draggable"
:list="item.list"
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
:clone="cloneComponent"
draggable=".components-item"
:sort="false"
@end="onEnd"
>
<div
v-for="(element, index) in item.list"
:key="index"
class="components-item"
@click="addComponent(element)"
>
<div class="components-body">
<svg-icon :icon-class="element.__config__.tagIcon" />
{{ element.__config__.label }}
</div>
</div>
</draggable>
</div>
</div>
</el-scrollbar>
</div>
<div class="center-board">
<div class="action-bar">
<!-- <el-button icon="el-icon-video-play" type="text" @click="run">
运行
</el-button>
<el-button icon="el-icon-view" type="text" @click="showJson">
查看json
</el-button>
<el-button icon="el-icon-download" type="text" @click="download">
导出vue文件
</el-button>
<el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">
复制代码
</el-button>-->
<el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">
清空
</el-button>
</div>
<el-scrollbar class="center-scrollbar">
<el-row class="center-board-row" :gutter="formConf.gutter">
<el-form
:size="formConf.size"
:label-position="formConf.labelPosition"
:disabled="formConf.disabled"
:label-width="formConf.labelWidth + 'px'"
>
<draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup">
<draggable-item
v-for="(item, index) in drawingList"
:key="item.renderKey"
:drawing-list="drawingList"
:current-item="item"
:index="index"
:active-id="activeId"
:form-conf="formConf"
@activeItem="activeFormItem"
@copyItem="drawingItemCopy"
@deleteItem="drawingItemDelete"
/>
</draggable>
<div v-show="!drawingList.length" class="empty-info">
从左侧拖入或点选组件进行表单设计
</div>
</el-form>
</el-row>
</el-scrollbar>
</div>
<right-panel
:active-data="activeData"
:form-conf="formConf"
:show-field="!!drawingList.length"
@tag-change="tagChange"
@fetch-data="fetchData"
/>
<form-drawer
:visible.sync="drawerVisible"
:form-data="formData"
size="100%"
:generate-conf="generateConf"
/>
<json-drawer
size="60%"
:visible.sync="jsonDrawerVisible"
:json-str="JSON.stringify(formData)"
@refresh="refreshJson"
/>
<code-type-dialog
:visible.sync="dialogVisible"
title="选择生成类型"
:show-file-name="showFileName"
@confirm="generate"
/>
<input id="copyNode" type="hidden">
</div>
</template>
<script>
import draggable from 'vuedraggable'
import { debounce } from 'throttle-debounce'
import { saveAs } from 'file-saver'
import ClipboardJS from 'clipboard'
import render from '@/components/render/render'
import FormDrawer from './FormDrawer'
import JsonDrawer from './JsonDrawer'
import RightPanel from './RightPanel'
import {
inputComponents, selectComponents, layoutComponents, formConf
} from '@/components/generator/config'
import {
exportDefault, beautifierConf, isNumberStr, titleCase, deepClone, isObjectObject
} from '@/utils/index'
import {
makeUpHtml, vueTemplate, vueScript, cssStyle
} from '@/components/generator/html'
import { makeUpJs } from '@/components/generator/js'
import { makeUpCss } from '@/components/generator/css'
import drawingDefalut from '@/components/generator/drawingDefalut'
import logo from '@/assets/logo/logo.png'
import CodeTypeDialog from './CodeTypeDialog'
import DraggableItem from './DraggableItem'
import {
getDrawingList, saveDrawingList, getIdGlobal, saveIdGlobal, getFormConf, getItem
} from '@/utils/db'
import loadBeautifier from '@/utils/loadBeautifier'
let beautifier
const emptyActiveData = { style: {}, autosize: {} }
let oldActiveId
let tempActiveData
// const drawingListInDB = getDrawingList()
// const formConfInDB = getFormConf()
const idGlobal = getIdGlobal()
export default {
components: {
draggable,
render,
FormDrawer,
JsonDrawer,
RightPanel,
CodeTypeDialog,
DraggableItem
},
data() {
return {
logo,
idGlobal,
formConf,
inputComponents,
selectComponents,
layoutComponents,
labelWidth: 100,
drawingList: drawingDefalut,
drawingData: {},
activeId: drawingDefalut[0].formId,
drawerVisible: false,
formData: {},
dialogVisible: false,
jsonDrawerVisible: false,
generateConf: null,
showFileName: false,
activeData: drawingDefalut[0],
saveDrawingListDebounce: debounce(340, saveDrawingList),
saveIdGlobalDebounce: debounce(340, saveIdGlobal),
leftComponents: [
{
title: '输入型组件',
list: inputComponents
},
{
title: '选择型组件',
list: selectComponents
},
{
title: '布局型组件',
list: layoutComponents
}
]
}
},
computed: {
},
watch: {
// eslint-disable-next-line func-names
'activeData.__config__.label': function (val, oldVal) {
if (
this.activeData.placeholder === undefined
|| !this.activeData.__config__.tag
|| oldActiveId !== this.activeId
) {
return
}
this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val
},
activeId: {
handler(val) {
oldActiveId = val
},
immediate: true
},
drawingList: {
handler(val) {
this.saveDrawingListDebounce(val)
if (val.length === 0) this.idGlobal = 100
},
deep: true
},
idGlobal: {
handler(val) {
this.saveIdGlobalDebounce(val)
},
immediate: true
}
},
mounted() {
const drawingListInDB = getItem()
if (Array.isArray(drawingListInDB) && drawingListInDB.length > 0) {
this.drawingList = drawingListInDB
} else {
this.drawingList = drawingDefalut
}
const formConfInDB = getFormConf()
this.activeFormItem(this.drawingList[0])
if (formConfInDB) {
this.formConf = formConfInDB
}
loadBeautifier(btf => {
beautifier = btf
})
const clipboard = new ClipboardJS('#copyNode', {
text: trigger => {
const codeStr = this.generateCode()
this.$notify({
title: '成功',
message: '代码已复制到剪切板,可粘贴。',
type: 'success'
})
return codeStr
}
})
clipboard.on('error', e => {
this.$message.error('代码复制失败')
})
},
methods: {
setObjectValueReduce(obj, strKeys, data) {
const arr = strKeys.split('.')
arr.reduce((pre, item, i) => {
if (arr.length === i + 1) {
pre[item] = data
} else if (!isObjectObject(pre[item])) {
pre[item] = {}
}
return pre[item]
}, obj)
},
setRespData(component, resp) {
const { dataPath, renderKey, dataConsumer } = component.__config__
if (!dataPath || !dataConsumer) return
const respData = dataPath.split('.').reduce((pre, item) => pre[item], resp)
// 将请求回来的数据,赋值到指定属性。
// 以el-tabel为例,根据Element文档,应该将数据赋值给el-tabel的data属性,所以dataConsumer的值应为'data';
// 此时赋值代码可写成 component[dataConsumer] = respData;
// 但为支持更深层级的赋值(如:dataConsumer的值为'options.data'),使用setObjectValueReduce
this.setObjectValueReduce(component, dataConsumer, respData)
const i = this.drawingList.findIndex(item => item.__config__.renderKey === renderKey)
if (i > -1) this.$set(this.drawingList, i, component)
},
fetchData(component) {
const { dataType, method, url } = component.__config__
if (dataType === 'dynamic' && method && url) {
this.setLoading(component, true)
this.$axios({
method,
url
}).then(resp => {
this.setLoading(component, false)
this.setRespData(component, resp.data)
})
}
},
setLoading(component, val) {
const { directives } = component
if (Array.isArray(directives)) {
const t = directives.find(d => d.name === 'loading')
if (t) t.value = val
}
},
activeFormItem(currentItem) {
this.activeData = currentItem
this.activeId = currentItem.__config__.formId
},
onEnd(obj) {
if (obj.from !== obj.to) {
this.fetchData(tempActiveData)
this.activeData = tempActiveData
this.activeId = this.idGlobal
}
},
addComponent(item) {
const clone = this.cloneComponent(item)
this.fetchData(clone)
this.drawingList.push(clone)
this.activeFormItem(clone)
},
cloneComponent(origin) {
const clone = deepClone(origin)
const config = clone.__config__
config.span = this.formConf.span // 生成代码时,会根据span做精简判断
this.createIdAndKey(clone)
clone.placeholder !== undefined && (clone.placeholder += config.label)
tempActiveData = clone
return tempActiveData
},
createIdAndKey(item) {
const config = item.__config__
config.formId = ++this.idGlobal
config.renderKey = `${config.formId}${+new Date()}` // 改变renderKey后可以实现强制更新组件
if (config.layout === 'colFormItem') {
item.__vModel__ = `field${this.idGlobal}`
} else if (config.layout === 'rowFormItem') {
config.componentName = `row${this.idGlobal}`
!Array.isArray(config.children) && (config.children = [])
delete config.label // rowFormItem无需配置label属性
}
if (Array.isArray(config.children)) {
config.children = config.children.map(childItem => this.createIdAndKey(childItem))
}
return item
},
AssembleFormData() {
this.formData = {
fields: deepClone(this.drawingList),
// ...this.formConf
}
},
generate(data) {
const func = this[`exec${titleCase(this.operationType)}`]
this.generateConf = data
func && func(data)
},
execRun(data) {
this.AssembleFormData()
this.drawerVisible = true
},
execDownload(data) {
const codeStr = this.generateCode()
const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
saveAs(blob, data.fileName)
},
execCopy(data) {
document.getElementById('copyNode').click()
},
empty() {
this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(
() => {
this.drawingList = []
this.idGlobal = 100
}
)
},
drawingItemCopy(item, list) {
let clone = deepClone(item)
clone = this.createIdAndKey(clone)
list.push(clone)
this.activeFormItem(clone)
},
drawingItemDelete(index, list) {
list.splice(index, 1)
this.$nextTick(() => {
const len = this.drawingList.length
if (len) {
this.activeFormItem(this.drawingList[len - 1])
}
})
},
generateCode() {
const { type } = this.generateConf
this.AssembleFormData()
const script = vueScript(makeUpJs(this.formData, type))
const html = vueTemplate(makeUpHtml(this.formData, type))
const css = cssStyle(makeUpCss(this.formData))
return beautifier.html(html + script + css, beautifierConf.html)
},
showJson() {
this.AssembleFormData()
this.jsonDrawerVisible = true
},
download() {
this.dialogVisible = true
this.showFileName = true
this.operationType = 'download'
},
run() {
this.dialogVisible = true
this.showFileName = false
this.operationType = 'run'
},
copy() {
this.dialogVisible = true
this.showFileName = false
this.operationType = 'copy'
},
tagChange(newTag) {
newTag = this.cloneComponent(newTag)
const config = newTag.__config__
newTag.__vModel__ = this.activeData.__vModel__
config.formId = this.activeId
config.span = this.activeData.__config__.span
this.activeData.__config__.tag = config.tag
this.activeData.__config__.tagIcon = config.tagIcon
this.activeData.__config__.document = config.document
if (typeof this.activeData.__config__.defaultValue === typeof config.defaultValue) {
config.defaultValue = this.activeData.__config__.defaultValue
}
Object.keys(newTag).forEach(key => {
if (this.activeData[key] !== undefined) {
newTag[key] = this.activeData[key]
}
})
this.activeData = newTag
this.updateDrawingList(newTag, this.drawingList)
},
updateDrawingList(newTag, list) {
const index = list.findIndex(item => item.__config__.formId === this.activeId)
if (index > -1) {
list.splice(index, 1, newTag)
} else {
list.forEach(item => {
if (Array.isArray(item.__config__.children)) this.updateDrawingList(newTag, item.__config__.children)
})
}
},
refreshJson(data) {
this.drawingList = deepClone(data.fields)
delete data.fields
this.formConf = data
},
getJson(){
this.AssembleFormData()
this.formData.formBtns = false
return this.formData
}
}
}
</script>
<style lang='scss'>
$selectedColor: #f6f7ff;
$lighterBlue: #409EFF;
.container {
position: relative;
width: 100%;
height: 100%;
}
.components-list {
padding: 8px;
box-sizing: border-box;
height: 100%;
.components-item {
display: inline-block;
width: 48%;
margin: 1%;
transition: transform 0ms !important;
}
}
.components-draggable{
padding-bottom: 20px;
}
.components-title{
font-size: 14px;
color: #222;
margin: 6px 2px;
.svg-icon{
color: #666;
font-size: 18px;
}
}
.components-body {
padding: 8px 10px;
background: $selectedColor;
font-size: 12px;
cursor: move;
border: 1px dashed $selectedColor;
border-radius: 3px;
.svg-icon{
color: #777;
font-size: 15px;
}
&:hover {
border: 1px dashed #787be8;
color: #787be8;
.svg-icon {
color: #787be8;
}
}
}
.left-board {
width: 260px;
position: absolute;
left: 0;
top: 0;
height: 100vh;
}
.left-scrollbar{
height: calc(100vh - 42px);
overflow: hidden;
}
.center-scrollbar {
height: calc(100vh - 42px);
overflow: hidden;
border-left: 1px solid #f1e8e8;
border-right: 1px solid #f1e8e8;
box-sizing: border-box;
}
.center-board {
height: 100vh;
width: auto;
margin: 0 350px 0 260px;
box-sizing: border-box;
}
.empty-info{
position: absolute;
top: 46%;
left: 0;
right: 0;
text-align: center;
font-size: 18px;
color: #ccb1ea;
letter-spacing: 4px;
}
.action-bar{
position: relative;
height: 42px;
text-align: right;
padding: 0 15px;
box-sizing: border-box;;
border: 1px solid #f1e8e8;
border-top: none;
border-left: none;
.delete-btn{
color: #F56C6C;
}
}
.logo-wrapper{
position: relative;
height: 42px;
background: #fff;
border-bottom: 1px solid #f1e8e8;
box-sizing: border-box;
}
.logo{
position: absolute;
left: 12px;
top: 6px;
line-height: 30px;
color: #00afff;
font-weight: 600;
font-size: 17px;
white-space: nowrap;
> img{
width: 30px;
height: 30px;
vertical-align: top;
}
.github{
display: inline-block;
vertical-align: sub;
margin-left: 15px;
> img{
height: 22px;
}
}
}
.center-board-row {
padding: 12px 12px 15px 12px;
box-sizing: border-box;
& > .el-form {
// 69 = 12+15+42
height: calc(100vh - 69px);
}
}
.drawing-board {
height: 100%;
position: relative;
.components-body {
padding: 0;
margin: 0;
font-size: 0;
}
.sortable-ghost {
position: relative;
display: block;
overflow: hidden;
&::before {
content: " ";
position: absolute;
left: 0;
right: 0;
top: 0;
height: 3px;
background: rgb(89, 89, 223);
z-index: 2;
}
}
.components-item.sortable-ghost {
width: 100%;
height: 60px;
background-color: $selectedColor;
}
.active-from-item {
& > .el-form-item{
background: $selectedColor;
border-radius: 6px;
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: initial;
}
& > .component-name{
color: $lighterBlue;
}
}
.el-form-item{
margin-bottom: 15px;
}
}
.drawing-item{
position: relative;
cursor: move;
&.unfocus-bordered:not(.active-from-item) > div:first-child {
border: 1px dashed #ccc;
}
.el-form-item{
padding: 12px 10px;
}
}
.drawing-row-item{
position: relative;
cursor: move;
box-sizing: border-box;
border: 1px dashed #ccc;
border-radius: 3px;
padding: 0 2px;
margin-bottom: 15px;
.drawing-row-item {
margin-bottom: 2px;
}
.el-col{
margin-top: 22px;
}
.el-form-item{
margin-bottom: 0;
}
.drag-wrapper{
min-height: 80px;
}
&.active-from-item{
border: 1px dashed $lighterBlue;
}
.component-name{
position: absolute;
top: 0;
left: 0;
font-size: 12px;
color: #bbb;
display: inline-block;
padding: 0 6px;
}
}
.drawing-item, .drawing-row-item{
&:hover {
& > .el-form-item{
background: $selectedColor;
border-radius: 6px;
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: initial;
}
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: none;
position: absolute;
top: -10px;
width: 22px;
height: 22px;
line-height: 22px;
text-align: center;
border-radius: 50%;
font-size: 12px;
border: 1px solid;
cursor: pointer;
z-index: 1;
}
& > .drawing-item-copy{
right: 56px;
border-color: $lighterBlue;
color: $lighterBlue;
background: #fff;
&:hover{
background: $lighterBlue;
color: #fff;
}
}
& > .drawing-item-delete{
right: 24px;
border-color: #F56C6C;
color: #F56C6C;
background: #fff;
&:hover{
background: #F56C6C;
color: #fff;
}
}
}
</style>
- proce —> fg ----> JsonDrawer.vue
<template>
<div>
<el-drawer v-bind="$attrs" v-on="$listeners" @opened="onOpen" @close="onClose">
<div class="action-bar" :style="{'text-align': 'left'}">
<span class="bar-btn" @click="refresh">
<i class="el-icon-refresh" />
刷新
</span>
<span ref="copyBtn" class="bar-btn copy-json-btn">
<i class="el-icon-document-copy" />
复制JSON
</span>
<span class="bar-btn" @click="exportJsonFile">
<i class="el-icon-download" />
导出JSON文件
</span>
<span class="bar-btn delete-btn" @click="$emit('update:visible', false)">
<i class="el-icon-circle-close" />
关闭
</span>
</div>
<div id="editorJson" class="json-editor" />
</el-drawer>
</div>
</template>
<script>
import { beautifierConf } from '@/utils/index'
import ClipboardJS from 'clipboard'
import { saveAs } from 'file-saver'
import loadMonaco from '@/utils/loadMonaco'
import loadBeautifier from '@/utils/loadBeautifier'
let beautifier
let monaco
export default {
components: {},
props: {
jsonStr: {
type: String,
required: true
}
},
data() {
return {}
},
computed: {},
watch: {},
created() {},
mounted() {
window.addEventListener('keydown', this.preventDefaultSave)
const clipboard = new ClipboardJS('.copy-json-btn', {
text: trigger => {
this.$notify({
title: '成功',
message: '代码已复制到剪切板,可粘贴。',
type: 'success'
})
return this.beautifierJson
}
})
clipboard.on('error', e => {
this.$message.error('代码复制失败')
})
},
beforeDestroy() {
window.removeEventListener('keydown', this.preventDefaultSave)
},
methods: {
preventDefaultSave(e) {
if (e.key === 's' && (e.metaKey || e.ctrlKey)) {
e.preventDefault()
}
},
onOpen() {
loadBeautifier(btf => {
beautifier = btf
this.beautifierJson = beautifier.js(this.jsonStr, beautifierConf.js)
loadMonaco(val => {
monaco = val
this.setEditorValue('editorJson', this.beautifierJson)
})
})
},
onClose() {},
setEditorValue(id, codeStr) {
if (this.jsonEditor) {
this.jsonEditor.setValue(codeStr)
} else {
this.jsonEditor = monaco.editor.create(document.getElementById(id), {
value: codeStr,
theme: 'vs-dark',
language: 'json',
automaticLayout: true
})
// ctrl + s 刷新
this.jsonEditor.onKeyDown(e => {
if (e.keyCode === 49 && (e.metaKey || e.ctrlKey)) {
this.refresh()
}
})
}
},
exportJsonFile() {
this.$prompt('文件名:', '导出文件', {
inputValue: `${+new Date()}.json`,
closeOnClickModal: false,
inputPlaceholder: '请输入文件名'
}).then(({ value }) => {
if (!value) value = `${+new Date()}.json`
const codeStr = this.jsonEditor.getValue()
const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
saveAs(blob, value)
})
},
refresh() {
try {
this.$emit('refresh', JSON.parse(this.jsonEditor.getValue()))
} catch (error) {
this.$notify({
title: '错误',
message: 'JSON格式错误,请检查',
type: 'error'
})
}
}
}
}
</script>
<style lang="scss" scoped>
@import '@/styles/mixin.scss';
::v-deep .el-drawer__header {
display: none;
}
@include action-bar;
.json-editor{
height: calc(100vh - 33px);
}
</style>
- proce —> fg ----> ResourceDialog.vue
<template>
<div>
<el-dialog
v-bind="$attrs"
title="外部资源引用"
width="600px"
:close-on-click-modal="false"
v-on="$listeners"
@open="onOpen"
@close="onClose"
>
<el-input
v-for="(item, index) in resources"
:key="index"
v-model="resources[index]"
class="url-item"
placeholder="请输入 css 或 js 资源路径"
prefix-icon="el-icon-link"
clearable
>
<el-button
slot="append"
icon="el-icon-delete"
@click="deleteOne(index)"
/>
</el-input>
<el-button-group class="add-item">
<el-button
plain
@click="addOne('https://lib.baomitu.com/jquery/1.8.3/jquery.min.js')"
>
jQuery1.8.3
</el-button>
<el-button
plain
@click="addOne('https://unpkg.com/http-vue-loader')"
>
http-vue-loader
</el-button>
<el-button
icon="el-icon-circle-plus-outline"
plain
@click="addOne('')"
>
添加其他
</el-button>
</el-button-group>
<div slot="footer">
<el-button @click="close">
取消
</el-button>
<el-button
type="primary"
@click="handelConfirm"
>
确定
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { deepClone } from '@/utils/index'
export default {
components: {},
inheritAttrs: false,
props: ['originResource'],
data() {
return {
resources: null
}
},
computed: {},
watch: {},
created() {},
mounted() {},
methods: {
onOpen() {
this.resources = this.originResource.length ? deepClone(this.originResource) : ['']
},
onClose() {
},
close() {
this.$emit('update:visible', false)
},
handelConfirm() {
const results = this.resources.filter(item => !!item) || []
this.$emit('save', results)
this.close()
if (results.length) {
this.resources = results
}
},
deleteOne(index) {
this.resources.splice(index, 1)
},
addOne(url) {
if (this.resources.indexOf(url) > -1) {
this.$message('资源已存在')
} else {
this.resources.push(url)
}
}
}
}
</script>
<style lang="scss" scoped>
.add-item{
margin-top: 8px;
}
.url-item{
margin-bottom: 12px;
}
</style>
- proce —> fg ----> RightPanel.vue
<template>
<div class="right-board">
<el-tabs v-model="currentTab" class="center-tabs">
<el-tab-pane label="组件属性" name="field" />
<el-tab-pane label="表单属性" name="form" />
</el-tabs>
<div class="field-box">
<a class="document-link" target="_blank" :href="documentLink" title="查看组件文档">
<i class="el-icon-link" />
</a>
<el-scrollbar class="right-scrollbar">
<!-- 组件属性 -->
<el-form v-show="currentTab==='field' && showField" size="small" label-width="90px">
<el-form-item v-if="activeData.__config__.changeTag" label="组件类型">
<el-select
v-model="activeData.__config__.tagIcon"
placeholder="请选择组件类型"
:style="{width: '100%'}"
@change="tagChange"
>
<el-option-group v-for="group in tagList" :key="group.label" :label="group.label">
<el-option
v-for="item in group.options"
:key="item.__config__.label"
:label="item.__config__.label"
:value="item.__config__.tagIcon"
>
<svg-icon class="node-icon" :icon-class="item.__config__.tagIcon" />
<span> {{ item.__config__.label }}</span>
</el-option>
</el-option-group>
</el-select>
</el-form-item>
<el-form-item v-if="activeData.__vModel__!==undefined" label="字段名">
<el-input v-model="activeData.__vModel__" placeholder="请输入字段名(v-model)" />
</el-form-item>
<el-form-item v-if="activeData.__config__.componentName!==undefined" label="组件名">
{{ activeData.__config__.componentName }}
</el-form-item>
<el-form-item v-if="activeData.__config__.label!==undefined" label="标题">
<el-input v-model="activeData.__config__.label" placeholder="请输入标题" @input="changeRenderKey" />
</el-form-item>
<el-form-item v-if="activeData.placeholder!==undefined" label="占位提示">
<el-input v-model="activeData.placeholder" placeholder="请输入占位提示" @input="changeRenderKey" />
</el-form-item>
<el-form-item v-if="activeData['start-placeholder']!==undefined" label="开始占位">
<el-input v-model="activeData['start-placeholder']" placeholder="请输入占位提示" />
</el-form-item>
<el-form-item v-if="activeData['end-placeholder']!==undefined" label="结束占位">
<el-input v-model="activeData['end-placeholder']" placeholder="请输入占位提示" />
</el-form-item>
<el-form-item v-if="activeData.__config__.span!==undefined" label="表单栅格">
<el-slider v-model="activeData.__config__.span" :max="24" :min="1" :marks="{12:''}" @change="spanChange" />
</el-form-item>
<el-form-item v-if="activeData.__config__.layout==='rowFormItem'&&activeData.gutter!==undefined" label="栅格间隔">
<el-input-number v-model="activeData.gutter" :min="0" placeholder="栅格间隔" />
</el-form-item>
<el-form-item v-if="activeData.__config__.layout==='rowFormItem'&&activeData.type!==undefined" label="布局模式">
<el-radio-group v-model="activeData.type">
<el-radio-button label="default" />
<el-radio-button label="flex" />
</el-radio-group>
</el-form-item>
<el-form-item v-if="activeData.justify!==undefined&&activeData.type==='flex'" label="水平排列">
<el-select v-model="activeData.justify" placeholder="请选择水平排列" :style="{width: '100%'}">
<el-option
v-for="(item, index) in justifyOptions"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item v-if="activeData.align!==undefined&&activeData.type==='flex'" label="垂直排列">
<el-radio-group v-model="activeData.align">
<el-radio-button label="top" />
<el-radio-button label="middle" />
<el-radio-button label="bottom" />
</el-radio-group>
</el-form-item>
<el-form-item v-if="activeData.__config__.labelWidth!==undefined" label="标签宽度">
<el-input v-model.number="activeData.__config__.labelWidth" type="number" placeholder="请输入标签宽度" />
</el-form-item>
<el-form-item v-if="activeData.style&&activeData.style.width!==undefined" label="组件宽度">
<el-input v-model="activeData.style.width" placeholder="请输入组件宽度" clearable />
</el-form-item>
<el-form-item v-if="activeData.__vModel__!==undefined" label="默认值">
<el-input
:value="setDefaultValue(activeData.__config__.defaultValue)"
placeholder="请输入默认值"
@input="onDefaultValueInput"
/>
</el-form-item>
<el-form-item v-if="activeData.__config__.tag==='el-checkbox-group'" label="至少应选">
<el-input-number
:value="activeData.min"
:min="0"
placeholder="至少应选"
@input="$set(activeData, 'min', $event?$event:undefined)"
/>
</el-form-item>
<el-form-item v-if="activeData.__config__.tag==='el-checkbox-group'" label="最多可选">
<el-input-number
:value="activeData.max"
:min="0"
placeholder="最多可选"
@input="$set(activeData, 'max', $event?$event:undefined)"
/>
</el-form-item>
<el-form-item v-if="activeData.__slot__&&activeData.__slot__.prepend!==undefined" label="前缀">
<el-input v-model="activeData.__slot__.prepend" placeholder="请输入前缀" />
</el-form-item>
<el-form-item v-if="activeData.__slot__&&activeData.__slot__.append!==undefined" label="后缀">
<el-input v-model="activeData.__slot__.append" placeholder="请输入后缀" />
</el-form-item>
<el-form-item v-if="activeData['prefix-icon']!==undefined" label="前图标">
<el-input v-model="activeData['prefix-icon']" placeholder="请输入前图标名称">
<el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('prefix-icon')">
选择
</el-button>
</el-input>
</el-form-item>
<el-form-item v-if="activeData['suffix-icon'] !== undefined" label="后图标">
<el-input v-model="activeData['suffix-icon']" placeholder="请输入后图标名称">
<el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('suffix-icon')">
选择
</el-button>
</el-input>
</el-form-item>
<el-form-item
v-if="activeData['icon']!==undefined && activeData.__config__.tag === 'el-button'"
label="按钮图标"
>
<el-input v-model="activeData['icon']" placeholder="请输入按钮图标名称">
<el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('icon')">
选择
</el-button>
</el-input>
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="选项分隔符">
<el-input v-model="activeData.separator" placeholder="请输入选项分隔符" />
</el-form-item>
<el-form-item v-if="activeData.autosize !== undefined" label="最小行数">
<el-input-number v-model="activeData.autosize.minRows" :min="1" placeholder="最小行数" />
</el-form-item>
<el-form-item v-if="activeData.autosize !== undefined" label="最大行数">
<el-input-number v-model="activeData.autosize.maxRows" :min="1" placeholder="最大行数" />
</el-form-item>
<el-form-item v-if="isShowMin" label="最小值">
<el-input-number v-model="activeData.min" placeholder="最小值" />
</el-form-item>
<el-form-item v-if="isShowMax" label="最大值">
<el-input-number v-model="activeData.max" placeholder="最大值" />
</el-form-item>
<el-form-item v-if="activeData.height!==undefined" label="组件高度">
<el-input-number v-model="activeData.height" placeholder="高度" @input="changeRenderKey" />
</el-form-item>
<el-form-item v-if="isShowStep" label="步长">
<el-input-number v-model="activeData.step" placeholder="步数" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-input-number'" label="精度">
<el-input-number v-model="activeData.precision" :min="0" placeholder="精度" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-input-number'" label="按钮位置">
<el-radio-group v-model="activeData['controls-position']">
<el-radio-button label="">
默认
</el-radio-button>
<el-radio-button label="right">
右侧
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="activeData.maxlength !== undefined" label="最多输入">
<el-input v-model="activeData.maxlength" placeholder="请输入字符长度">
<template slot="append">
个字符
</template>
</el-input>
</el-form-item>
<el-form-item v-if="activeData['active-text'] !== undefined" label="开启提示">
<el-input v-model="activeData['active-text']" placeholder="请输入开启提示" />
</el-form-item>
<el-form-item v-if="activeData['inactive-text'] !== undefined" label="关闭提示">
<el-input v-model="activeData['inactive-text']" placeholder="请输入关闭提示" />
</el-form-item>
<el-form-item v-if="activeData['active-value'] !== undefined" label="开启值">
<el-input
:value="setDefaultValue(activeData['active-value'])"
placeholder="请输入开启值"
@input="onSwitchValueInput($event, 'active-value')"
/>
</el-form-item>
<el-form-item v-if="activeData['inactive-value'] !== undefined" label="关闭值">
<el-input
:value="setDefaultValue(activeData['inactive-value'])"
placeholder="请输入关闭值"
@input="onSwitchValueInput($event, 'inactive-value')"
/>
</el-form-item>
<el-form-item
v-if="activeData.type !== undefined && 'el-date-picker' === activeData.__config__.tag"
label="时间类型"
>
<el-select
v-model="activeData.type"
placeholder="请选择时间类型"
:style="{ width: '100%' }"
@change="dateTypeChange"
>
<el-option
v-for="(item, index) in dateOptions"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item v-if="activeData.name !== undefined" label="文件字段名">
<el-input v-model="activeData.name" placeholder="请输入上传文件字段名" />
</el-form-item>
<el-form-item v-if="activeData.accept !== undefined" label="文件类型">
<el-select
v-model="activeData.accept"
placeholder="请选择文件类型"
:style="{ width: '100%' }"
clearable
>
<el-option label="图片" value="image/*" />
<el-option label="视频" value="video/*" />
<el-option label="音频" value="audio/*" />
<el-option label="excel" value=".xls,.xlsx" />
<el-option label="word" value=".doc,.docx" />
<el-option label="pdf" value=".pdf" />
<el-option label="txt" value=".txt" />
</el-select>
</el-form-item>
<el-form-item v-if="activeData.__config__.fileSize !== undefined" label="文件大小">
<el-input v-model.number="activeData.__config__.fileSize" placeholder="请输入文件大小">
<el-select slot="append" v-model="activeData.__config__.sizeUnit" :style="{ width: '66px' }">
<el-option label="KB" value="KB" />
<el-option label="MB" value="MB" />
<el-option label="GB" value="GB" />
</el-select>
</el-input>
</el-form-item>
<el-form-item v-if="activeData.action !== undefined" label="上传地址">
<el-input v-model="activeData.action" placeholder="请输入上传地址" clearable />
</el-form-item>
<el-form-item v-if="activeData['list-type'] !== undefined" label="列表类型">
<el-radio-group v-model="activeData['list-type']" size="small">
<el-radio-button label="text">
text
</el-radio-button>
<el-radio-button label="picture">
picture
</el-radio-button>
<el-radio-button label="picture-card">
picture-card
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="activeData.type !== undefined && activeData.__config__.tag === 'el-button'"
label="按钮类型"
>
<el-select v-model="activeData.type" :style="{ width: '100%' }">
<el-option label="primary" value="primary" />
<el-option label="success" value="success" />
<el-option label="warning" value="warning" />
<el-option label="danger" value="danger" />
<el-option label="info" value="info" />
<el-option label="text" value="text" />
</el-select>
</el-form-item>
<el-form-item
v-if="activeData.__config__.buttonText !== undefined"
v-show="'picture-card' !== activeData['list-type']"
label="按钮文字"
>
<el-input v-model="activeData.__config__.buttonText" placeholder="请输入按钮文字" />
</el-form-item>
<el-form-item
v-if="activeData.__config__.tag === 'el-button'"
label="按钮文字"
>
<el-input v-model="activeData.__slot__.default" placeholder="请输入按钮文字" />
</el-form-item>
<el-form-item v-if="activeData['range-separator'] !== undefined" label="分隔符">
<el-input v-model="activeData['range-separator']" placeholder="请输入分隔符" />
</el-form-item>
<el-form-item v-if="activeData['picker-options'] !== undefined" label="时间段">
<el-input
v-model="activeData['picker-options'].selectableRange"
placeholder="请输入时间段"
/>
</el-form-item>
<el-form-item v-if="activeData.format !== undefined" label="时间格式">
<el-input
:value="activeData.format"
placeholder="请输入时间格式"
@input="setTimeValue($event)"
/>
</el-form-item>
<template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.__config__.tag) > -1">
<el-divider>选项</el-divider>
<draggable
:list="activeData.__slot__.options"
:animation="340"
group="selectItem"
handle=".option-drag"
>
<div v-for="(item, index) in activeData.__slot__.options" :key="index" class="select-item">
<div class="select-line-icon option-drag">
<i class="el-icon-s-operation" />
</div>
<el-input v-model="item.label" placeholder="选项名" size="small" />
<el-input
placeholder="选项值"
size="small"
:value="item.value"
@input="setOptionValue(item, $event)"
/>
<div class="close-btn select-line-icon" @click="activeData.__slot__.options.splice(index, 1)">
<i class="el-icon-remove-outline" />
</div>
</div>
</draggable>
<div style="margin-left: 20px;">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="addSelectItem"
>
添加选项
</el-button>
</div>
<el-divider />
</template>
<template v-if="['el-cascader', 'el-table'].includes(activeData.__config__.tag)">
<el-divider>选项</el-divider>
<el-form-item v-if="activeData.__config__.dataType" label="数据类型">
<el-radio-group v-model="activeData.__config__.dataType" size="small">
<el-radio-button label="dynamic">
动态数据
</el-radio-button>
<el-radio-button label="static">
静态数据
</el-radio-button>
</el-radio-group>
</el-form-item>
<template v-if="activeData.__config__.dataType === 'dynamic'">
<el-form-item label="接口地址">
<el-input
v-model="activeData.__config__.url"
:title="activeData.__config__.url"
placeholder="请输入接口地址"
clearable
@blur="$emit('fetch-data', activeData)"
>
<el-select
slot="prepend"
v-model="activeData.__config__.method"
:style="{width: '85px'}"
@change="$emit('fetch-data', activeData)"
>
<el-option label="get" value="get" />
<el-option label="post" value="post" />
<el-option label="put" value="put" />
<el-option label="delete" value="delete" />
</el-select>
</el-input>
</el-form-item>
<el-form-item label="数据位置">
<el-input
v-model="activeData.__config__.dataPath"
placeholder="请输入数据位置"
@blur="$emit('fetch-data', activeData)"
/>
</el-form-item>
<template v-if="activeData.props && activeData.props.props">
<el-form-item label="标签键名">
<el-input v-model="activeData.props.props.label" placeholder="请输入标签键名" />
</el-form-item>
<el-form-item label="值键名">
<el-input v-model="activeData.props.props.value" placeholder="请输入值键名" />
</el-form-item>
<el-form-item label="子级键名">
<el-input v-model="activeData.props.props.children" placeholder="请输入子级键名" />
</el-form-item>
</template>
</template>
<!-- 级联选择静态树 -->
<el-tree
v-if="activeData.__config__.dataType === 'static'"
draggable
:data="activeData.options"
node-key="id"
:expand-on-click-node="false"
:render-content="renderContent"
/>
<div v-if="activeData.__config__.dataType === 'static'" style="margin-left: 20px">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="addTreeItem"
>
添加父级
</el-button>
</div>
<el-divider />
</template>
<el-form-item v-if="activeData.__config__.optionType !== undefined" label="选项样式">
<el-radio-group v-model="activeData.__config__.optionType">
<el-radio-button label="default">
默认
</el-radio-button>
<el-radio-button label="button">
按钮
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="activeData['active-color'] !== undefined" label="开启颜色">
<el-color-picker v-model="activeData['active-color']" />
</el-form-item>
<el-form-item v-if="activeData['inactive-color'] !== undefined" label="关闭颜色">
<el-color-picker v-model="activeData['inactive-color']" />
</el-form-item>
<el-form-item v-if="activeData.__config__.showLabel !== undefined
&& activeData.__config__.labelWidth !== undefined" label="显示标签"
>
<el-switch v-model="activeData.__config__.showLabel" />
</el-form-item>
<el-form-item v-if="activeData.branding !== undefined" label="品牌烙印">
<el-switch v-model="activeData.branding" @input="changeRenderKey" />
</el-form-item>
<el-form-item v-if="activeData['allow-half'] !== undefined" label="允许半选">
<el-switch v-model="activeData['allow-half']" />
</el-form-item>
<el-form-item v-if="activeData['show-text'] !== undefined" label="辅助文字">
<el-switch v-model="activeData['show-text']" @change="rateTextChange" />
</el-form-item>
<el-form-item v-if="activeData['show-score'] !== undefined" label="显示分数">
<el-switch v-model="activeData['show-score']" @change="rateScoreChange" />
</el-form-item>
<el-form-item v-if="activeData['show-stops'] !== undefined" label="显示间断点">
<el-switch v-model="activeData['show-stops']" />
</el-form-item>
<el-form-item v-if="activeData.range !== undefined" label="范围选择">
<el-switch v-model="activeData.range" @change="rangeChange" />
</el-form-item>
<el-form-item
v-if="activeData.__config__.border !== undefined && activeData.__config__.optionType === 'default'"
label="是否带边框"
>
<el-switch v-model="activeData.__config__.border" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-color-picker'" label="颜色格式">
<el-select
v-model="activeData['color-format']"
placeholder="请选择颜色格式"
:style="{ width: '100%' }"
clearable
@change="colorFormatChange"
>
<el-option
v-for="(item, index) in colorFormatOptions"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="activeData.size !== undefined &&
(activeData.__config__.optionType === 'button' ||
activeData.__config__.border ||
activeData.__config__.tag === 'el-color-picker' ||
activeData.__config__.tag === 'el-button')"
label="组件尺寸"
>
<el-radio-group v-model="activeData.size">
<el-radio-button label="medium">
中等
</el-radio-button>
<el-radio-button label="small">
较小
</el-radio-button>
<el-radio-button label="mini">
迷你
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="activeData['show-word-limit'] !== undefined" label="输入统计">
<el-switch v-model="activeData['show-word-limit']" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-input-number'" label="严格步数">
<el-switch v-model="activeData['step-strictly']" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="任选层级">
<el-switch v-model="activeData.props.props.checkStrictly" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="是否多选">
<el-switch v-model="activeData.props.props.multiple" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="展示全路径">
<el-switch v-model="activeData['show-all-levels']" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-cascader'" label="可否筛选">
<el-switch v-model="activeData.filterable" />
</el-form-item>
<el-form-item v-if="activeData.clearable !== undefined" label="能否清空">
<el-switch v-model="activeData.clearable" />
</el-form-item>
<el-form-item v-if="activeData.__config__.showTip !== undefined" label="显示提示">
<el-switch v-model="activeData.__config__.showTip" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-upload'" label="多选文件">
<el-switch v-model="activeData.multiple" />
</el-form-item>
<el-form-item v-if="activeData['auto-upload'] !== undefined" label="自动上传">
<el-switch v-model="activeData['auto-upload']" />
</el-form-item>
<el-form-item v-if="activeData.readonly !== undefined" label="是否只读">
<el-switch v-model="activeData.readonly" />
</el-form-item>
<el-form-item v-if="activeData.disabled !== undefined" label="是否禁用">
<el-switch v-model="activeData.disabled" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-select'" label="能否搜索">
<el-switch v-model="activeData.filterable" />
</el-form-item>
<el-form-item v-if="activeData.__config__.tag === 'el-select'" label="是否多选">
<el-switch v-model="activeData.multiple" @change="multipleChange" />
</el-form-item>
<el-form-item v-if="activeData.__config__.required !== undefined" label="是否必填">
<el-switch v-model="activeData.__config__.required" />
</el-form-item>
<template v-if="activeData.__config__.layoutTree">
<el-divider>布局结构树</el-divider>
<el-tree
:data="[activeData.__config__]"
:props="layoutTreeProps"
node-key="renderKey"
default-expand-all
draggable
>
<span slot-scope="{ node, data }">
<span class="node-label">
<svg-icon class="node-icon" :icon-class="data.__config__?data.__config__.tagIcon:data.tagIcon" />
{{ node.label }}
</span>
</span>
</el-tree>
</template>
<template v-if="Array.isArray(activeData.__config__.regList)">
<el-divider>正则校验</el-divider>
<div
v-for="(item, index) in activeData.__config__.regList"
:key="index"
class="reg-item"
>
<span class="close-btn" @click="activeData.__config__.regList.splice(index, 1)">
<i class="el-icon-close" />
</span>
<el-form-item label="表达式">
<el-input v-model="item.pattern" placeholder="请输入正则" />
</el-form-item>
<el-form-item label="错误提示" style="margin-bottom:0">
<el-input v-model="item.message" placeholder="请输入错误提示" />
</el-form-item>
</div>
<div style="margin-left: 20px">
<el-button icon="el-icon-circle-plus-outline" type="text" @click="addReg">
添加规则
</el-button>
</div>
</template>
</el-form>
<!-- 表单属性 -->
<el-form v-show="currentTab === 'form'" size="small" label-width="90px">
<el-form-item label="表单名">
<el-input v-model="formConf.formRef" placeholder="请输入表单名(ref)" />
</el-form-item>
<el-form-item label="表单模型">
<el-input v-model="formConf.formModel" placeholder="请输入数据模型" />
</el-form-item>
<el-form-item label="校验模型">
<el-input v-model="formConf.formRules" placeholder="请输入校验模型" />
</el-form-item>
<el-form-item label="表单尺寸">
<el-radio-group v-model="formConf.size">
<el-radio-button label="medium">
中等
</el-radio-button>
<el-radio-button label="small">
较小
</el-radio-button>
<el-radio-button label="mini">
迷你
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="标签对齐">
<el-radio-group v-model="formConf.labelPosition">
<el-radio-button label="left">
左对齐
</el-radio-button>
<el-radio-button label="right">
右对齐
</el-radio-button>
<el-radio-button label="top">
顶部对齐
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="标签宽度">
<el-input v-model.number="formConf.labelWidth" type="number" placeholder="请输入标签宽度" />
</el-form-item>
<el-form-item label="栅格间隔">
<el-input-number v-model="formConf.gutter" :min="0" placeholder="栅格间隔" />
</el-form-item>
<el-form-item label="禁用表单">
<el-switch v-model="formConf.disabled" />
</el-form-item>
<el-form-item label="表单按钮">
<el-switch v-model="formConf.formBtns" />
</el-form-item>
<el-form-item label="显示未选中组件边框">
<el-switch v-model="formConf.unFocusedComponentBorder" />
</el-form-item>
</el-form>
</el-scrollbar>
</div>
<treeNode-dialog :visible.sync="dialogVisible" title="添加选项" @commit="addNode" />
<icons-dialog :visible.sync="iconsVisible" :current="activeData[currentIconModel]" @select="setIcon" />
</div>
</template>
<script>
import { isArray } from 'util'
import TreeNodeDialog from './TreeNodeDialog'
import { isNumberStr } from '@/utils/index'
import IconsDialog from './IconsDialog'
import {
inputComponents, selectComponents, layoutComponents
} from '@/components/generator/config'
import { saveFormConf } from '@/utils/db'
const dateTimeFormat = {
date: 'yyyy-MM-dd',
week: 'yyyy 第 WW 周',
month: 'yyyy-MM',
year: 'yyyy',
datetime: 'yyyy-MM-dd HH:mm:ss',
daterange: 'yyyy-MM-dd',
monthrange: 'yyyy-MM',
datetimerange: 'yyyy-MM-dd HH:mm:ss'
}
// 使changeRenderKey在目标组件改变时可用
const needRerenderList = ['tinymce']
export default {
components: {
TreeNodeDialog,
IconsDialog
},
props: ['showField', 'activeData', 'formConf'],
data() {
return {
currentTab: 'field',
currentNode: null,
dialogVisible: false,
iconsVisible: false,
currentIconModel: null,
dateTypeOptions: [
{
label: '日(date)',
value: 'date'
},
{
label: '周(week)',
value: 'week'
},
{
label: '月(month)',
value: 'month'
},
{
label: '年(year)',
value: 'year'
},
{
label: '日期时间(datetime)',
value: 'datetime'
}
],
dateRangeTypeOptions: [
{
label: '日期范围(daterange)',
value: 'daterange'
},
{
label: '月范围(monthrange)',
value: 'monthrange'
},
{
label: '日期时间范围(datetimerange)',
value: 'datetimerange'
}
],
colorFormatOptions: [
{
label: 'hex',
value: 'hex'
},
{
label: 'rgb',
value: 'rgb'
},
{
label: 'rgba',
value: 'rgba'
},
{
label: 'hsv',
value: 'hsv'
},
{
label: 'hsl',
value: 'hsl'
}
],
justifyOptions: [
{
label: 'start',
value: 'start'
},
{
label: 'end',
value: 'end'
},
{
label: 'center',
value: 'center'
},
{
label: 'space-around',
value: 'space-around'
},
{
label: 'space-between',
value: 'space-between'
}
],
layoutTreeProps: {
label(data, node) {
const config = data.__config__
return data.componentName || `${config.label}: ${data.__vModel__}`
}
}
}
},
computed: {
documentLink() {
return (
this.activeData.__config__.document
|| 'https://element.eleme.cn/#/zh-CN/component/installation'
)
},
dateOptions() {
if (
this.activeData.type !== undefined
&& this.activeData.__config__.tag === 'el-date-picker'
) {
if (this.activeData['start-placeholder'] === undefined) {
return this.dateTypeOptions
}
return this.dateRangeTypeOptions
}
return []
},
tagList() {
return [
{
label: '输入型组件',
options: inputComponents
},
{
label: '选择型组件',
options: selectComponents
}
]
},
activeTag() {
return this.activeData.__config__.tag
},
isShowMin() {
return ['el-input-number', 'el-slider'].indexOf(this.activeTag) > -1
},
isShowMax() {
return ['el-input-number', 'el-slider', 'el-rate'].indexOf(this.activeTag) > -1
},
isShowStep() {
return ['el-input-number', 'el-slider'].indexOf(this.activeTag) > -1
}
},
watch: {
formConf: {
handler(val) {
saveFormConf(val)
},
deep: true
}
},
methods: {
addReg() {
this.activeData.__config__.regList.push({
pattern: '',
message: ''
})
},
addSelectItem() {
this.activeData.__slot__.options.push({
label: '',
value: ''
})
},
addTreeItem() {
++this.idGlobal
this.dialogVisible = true
this.currentNode = this.activeData.options
},
renderContent(h, { node, data, store }) {
return (
<div class="custom-tree-node">
<span>{node.label}</span>
<span class="node-operation">
<i on-click={() => this.append(data)}
class="el-icon-plus"
title="添加"
></i>
<i on-click={() => this.remove(node, data)}
class="el-icon-delete"
title="删除"
></i>
</span>
</div>
)
},
append(data) {
if (!data.children) {
this.$set(data, 'children', [])
}
this.dialogVisible = true
this.currentNode = data.children
},
remove(node, data) {
this.activeData.__config__.defaultValue = [] // 避免删除时报错
const { parent } = node
const children = parent.data.children || parent.data
const index = children.findIndex(d => d.id === data.id)
children.splice(index, 1)
},
addNode(data) {
this.currentNode.push(data)
},
setOptionValue(item, val) {
item.value = isNumberStr(val) ? +val : val
},
setDefaultValue(val) {
if (Array.isArray(val)) {
return val.join(',')
}
// if (['string', 'number'].indexOf(typeof val) > -1) {
// return val
// }
if (typeof val === 'boolean') {
return `${val}`
}
return val
},
onDefaultValueInput(str) {
if (isArray(this.activeData.__config__.defaultValue)) {
// 数组
this.$set(
this.activeData.__config__,
'defaultValue',
str.split(',').map(val => (isNumberStr(val) ? +val : val))
)
} else if (['true', 'false'].indexOf(str) > -1) {
// 布尔
this.$set(this.activeData.__config__, 'defaultValue', JSON.parse(str))
} else {
// 字符串和数字
this.$set(
this.activeData.__config__,
'defaultValue',
isNumberStr(str) ? +str : str
)
}
},
onSwitchValueInput(val, name) {
if (['true', 'false'].indexOf(val) > -1) {
this.$set(this.activeData, name, JSON.parse(val))
} else {
this.$set(this.activeData, name, isNumberStr(val) ? +val : val)
}
},
setTimeValue(val, type) {
const valueFormat = type === 'week' ? dateTimeFormat.date : val
this.$set(this.activeData.__config__, 'defaultValue', null)
this.$set(this.activeData, 'value-format', valueFormat)
this.$set(this.activeData, 'format', val)
},
spanChange(val) {
this.formConf.span = val
},
multipleChange(val) {
this.$set(this.activeData.__config__, 'defaultValue', val ? [] : '')
},
dateTypeChange(val) {
this.setTimeValue(dateTimeFormat[val], val)
},
rangeChange(val) {
this.$set(
this.activeData.__config__,
'defaultValue',
val ? [this.activeData.min, this.activeData.max] : this.activeData.min
)
},
rateTextChange(val) {
if (val) this.activeData['show-score'] = false
},
rateScoreChange(val) {
if (val) this.activeData['show-text'] = false
},
colorFormatChange(val) {
this.activeData.__config__.defaultValue = null
this.activeData['show-alpha'] = val.indexOf('a') > -1
this.activeData.__config__.renderKey = +new Date() // 更新renderKey,重新渲染该组件
},
openIconsDialog(model) {
this.iconsVisible = true
this.currentIconModel = model
},
setIcon(val) {
this.activeData[this.currentIconModel] = val
},
tagChange(tagIcon) {
let target = inputComponents.find(item => item.__config__.tagIcon === tagIcon)
if (!target) target = selectComponents.find(item => item.__config__.tagIcon === tagIcon)
this.$emit('tag-change', target)
},
changeRenderKey() {
if (needRerenderList.includes(this.activeData.__config__.tag)) {
this.activeData.__config__.renderKey = +new Date()
}
}
}
}
</script>
<style lang="scss" scoped>
.right-board {
width: 350px;
position: absolute;
right: 0;
top: 0;
padding-top: 3px;
.field-box {
position: relative;
height: calc(100vh - 42px);
box-sizing: border-box;
overflow: hidden;
}
.el-scrollbar {
height: 100%;
}
}
.select-item {
display: flex;
border: 1px dashed #fff;
box-sizing: border-box;
& .close-btn {
cursor: pointer;
color: #f56c6c;
}
& .el-input + .el-input {
margin-left: 4px;
}
}
.select-item + .select-item {
margin-top: 4px;
}
.select-item.sortable-chosen {
border: 1px dashed #409eff;
}
.select-line-icon {
line-height: 32px;
font-size: 22px;
padding: 0 4px;
color: #777;
}
.option-drag {
cursor: move;
}
.time-range {
.el-date-editor {
width: 227px;
}
::v-deep .el-icon-time {
display: none;
}
}
.document-link {
position: absolute;
display: block;
width: 26px;
height: 26px;
top: 0;
left: 0;
cursor: pointer;
background: #409eff;
z-index: 1;
border-radius: 0 0 6px 0;
text-align: center;
line-height: 26px;
color: #fff;
font-size: 18px;
}
.node-label{
font-size: 14px;
}
.node-icon{
color: #bebfc3;
}
</style>
- proce —> fg ----> TreeNodeDialog.vue
<template>
<div>
<el-dialog
v-bind="$attrs"
:close-on-click-modal="false"
:modal-append-to-body="false"
v-on="$listeners"
@open="onOpen"
@close="onClose"
>
<el-row :gutter="0">
<el-form
ref="elForm"
:model="formData"
:rules="rules"
size="small"
label-width="100px"
>
<el-col :span="24">
<el-form-item
label="选项名"
prop="label"
>
<el-input
v-model="formData.label"
placeholder="请输入选项名"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="选项值"
prop="value"
>
<el-input
v-model="formData.value"
placeholder="请输入选项值"
clearable
>
<el-select
slot="append"
v-model="dataType"
:style="{width: '100px'}"
>
<el-option
v-for="(item, index) in dataTypeOptions"
:key="index"
:label="item.label"
:value="item.value"
:disabled="item.disabled"
/>
</el-select>
</el-input>
</el-form-item>
</el-col>
</el-form>
</el-row>
<div slot="footer">
<el-button
type="primary"
@click="handelConfirm"
>
确定
</el-button>
<el-button @click="close">
取消
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { isNumberStr } from '@/utils/index'
import { getTreeNodeId, saveTreeNodeId } from '@/utils/db'
const id = getTreeNodeId()
export default {
components: {},
inheritAttrs: false,
props: [],
data() {
return {
id,
formData: {
label: undefined,
value: undefined
},
rules: {
label: [
{
required: true,
message: '请输入选项名',
trigger: 'blur'
}
],
value: [
{
required: true,
message: '请输入选项值',
trigger: 'blur'
}
]
},
dataType: 'string',
dataTypeOptions: [
{
label: '字符串',
value: 'string'
},
{
label: '数字',
value: 'number'
}
]
}
},
computed: {},
watch: {
// eslint-disable-next-line func-names
'formData.value': function (val) {
this.dataType = isNumberStr(val) ? 'number' : 'string'
},
id(val) {
saveTreeNodeId(val)
}
},
created() {},
mounted() {},
methods: {
onOpen() {
this.formData = {
label: undefined,
value: undefined
}
},
onClose() {},
close() {
this.$emit('update:visible', false)
},
handelConfirm() {
this.$refs.elForm.validate(valid => {
if (!valid) return
if (this.dataType === 'number') {
this.formData.value = parseFloat(this.formData.value)
}
this.formData.id = this.id++
this.$emit('commit', this.formData)
this.close()
})
}
}
}
</script>
<style lang="scss" scoped>
</style>
- proce —> form —> PermisForm.vue
<template>
<el-dialog title="谁可以发起" :visible.sync="visible" width="1440px" top="5vh" append-to-body>
<el-row type="flex">
<el-col :span="3"></el-col>
<el-col :span="14">
<el-radio-group v-model="pType" @change="selectType" size="medium">
<el-radio-button label="1">成员</el-radio-button>
<el-radio-button label="2">角色</el-radio-button>
</el-radio-group>
</el-col>
<el-col :span="3">
<el-button type="primary" @click="subData">确 定</el-button>
<el-button style="margin-left: 0px;" @click="cancleSub">取 消</el-button>
</el-col>
</el-row>
<el-row type="flex" style="margin-top: 25px; margin-bottom: 80px;" shadow="never">
<el-col :span="3"></el-col>
<el-col :span="20">
<el-transfer v-model="value" :data="datas" :titles="titles"></el-transfer>
</el-col>
<el-col :span="1"></el-col>
</el-row>
</el-dialog>
</template>
<script>
import { listUser } from '@/api/system/user'
import { listRole } from "@/api/system/role"
import { updateProce } from '@/api/fp/proce'
export default {
name: 'PermisForm',
data() {
return {
row: {},
value: [],
userVal: [],
roleVal: [],
datas: [],
loading: false,
visible: false,
pType: '1',
titles: ['未选成员', '已选成员']
}
},
created() {
},
methods: {
show(row) {
this.row = row
this.datas = []
this.userVal = this.formatVal(row.actionUserId)
this.roleVal = this.formatVal(row.actionRoleId)
this.value = this.userVal
this.titles = ['未选成员', '已选成员']
this.pType = '1'
this.visible = true
this.getList('1')
},
async getList(flag) {
this.loading = true
flag == '1' ? await listUser().then(response => {
let datas = []
response.rows.map(item => {
datas = [...datas, { key: item.userId, label: item.nickName }]
})
this.datas = datas
this.loading = false
}) : await listRole().then(response => {
let datas = []
response.rows.map(item => {
datas = [...datas, { key: item.roleId, label: item.roleName }]
})
this.datas = datas
this.loading = false
})
},
selectType(flag) {
let data = this.value
this.titles = flag == '1' ? ['未选成员', '已选成员'] : ['未选角色', '已选角色']
this.value = flag == '1'?this.userVal:this.roleVal
flag == '1'?this.roleVal = data:this.userVal = data
this.getList(flag)
},
cancleSub(){
this.visible = false
this.row = {}
},
subData(){
let ids = ''
this.value.map(d => {
ids += d + ','
})
let param = {
proId: this.row.proId,
actionUserId: this.pType == '1' && ids?ids.substring(0,ids.length-1):'',
actionRoleId: this.pType == '2' && ids?ids.substring(0,ids.length-1):'',
}
updateProce(param).then(res =>{
this.msgSuccess('设置成功!')
this.cancleSub()
this.$emit('getList')
})
},
formatVal(val){
let data = []
if(val){
val.split(',').map(item => {
data = [...data, Number(item)]
})
}
return data
},
}
}
</script>
<style>
.el-transfer-panel {
width: 391px;
}
</style>
- proce —> form —> UserForm.vue
<template>
<el-dialog :title="title" :visible.sync="visible" width="625px" top="5vh" append-to-body>
<el-transfer v-model="value" :data="datas" :titles="titles"></el-transfer>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="subUser">确 定</el-button>
<el-button @click="cancleSub">取 消</el-button>
</div>
</el-dialog>
</template>
<script>
import { listUser } from '@/api/system/user'
import { listRole } from "@/api/system/role"
export default {
name: 'UserForm',
data() {
return {
value: [],
datas: [],
loading: false,
visible: false,
titles: ['未选成员', '已选成员'],
title: '添加成员',
}
},
created() {
},
methods: {
show(row){
this.visible = true
this.row = row
this.value = row.value
this.getList(row.flag)
this.initBaseInfo(row.flag)
},
initBaseInfo(flag){
this.titles = ['未选角色', '已选角色']
this.title = '添加角色'
if(flag == '1'){
this.titles = ['未选成员', '已选成员']
this.title = '添加成员'
}
},
async getList(flag) {
this.loading = true
flag == '1' ? await listUser().then(response => {
let datas = []
response.rows.map(item => {
datas = [...datas, { key: item.userId, label: item.nickName }]
})
this.datas = datas
this.loading = false
}) : await listRole().then(response => {
let datas = []
response.rows.map(item => {
datas = [...datas, { key: item.roleId, label: item.roleName }]
})
this.datas = datas
this.loading = false
})
},
/*添加用户*/
subUser(){
let fpDefExams = []
this.value.map(item =>{
fpDefExams = [...fpDefExams, {
userId: this.row.flag == '1'?item:null,
roleId: this.row.flag == '2'?item:null,
emptyType: this.row.emptyType,
userNameDictText: this.row.flag == '1'?this.datas.filter(d => d.key == item)[0].label:null,
roleNameDictText: this.row.flag == '2'?this.datas.filter(d => d.key == item)[0].label:null
}]
})
this.$emit('setUserVal', {...this.row, userId: this.row.flag == '1'?this.value:null,roleId: this.row.flag == '2'?this.value:null, fpDefExams})
this.cancleSub()
},
cancleSub(){
this.visible = false
this.row = null
this.value = []
}
}
}
</script>
- proce —> index.vue
<template>
<div class="app-container">
<div v-if="flag=='1'">
<div class="demo-input-suffix">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px" @submit.native.prevent>
<el-form-item label="流程设计" prop="proName">
<el-input
placeholder="请输入流程名称进行搜索"
v-model="queryParams.proName"
prefix-icon="el-icon-search"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-row style="float: right;">
<el-button
type="primary"
plain
@click="handleAdd"
v-hasPermi="['fp:group:add']"
>新建分组
</el-button>
<!--<el-button>分组排序</el-button>-->
<el-button type="primary" icon="el-icon-plus" @click="createFp">创建新流程</el-button>
</el-row>
</el-form>
</div>
<div v-for="(item, index) in datas">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>{{item.groupName}}({{item.procs.length}})</span>
<el-link icon="el-icon-sort-up" :underline="false" style="float: right;"
@click="orderGroup(true, item, index)">向上
</el-link>
<el-link icon="el-icon-sort-down" :underline="false" style="float: right;"
@click="orderGroup(false, item, index)">向下
</el-link>
<el-dropdown style="float: right; padding: 0px 15px 0px 0">
<span class="el-dropdown-link">
<el-link :underline="false" icon="el-icon-setting">编辑分组</el-link>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>
<el-link :underline="false" @click="reName(item)">重命名</el-link>
</el-dropdown-item>
<el-dropdown-item>
<el-link :underline="false" @click="delGroupData(item)">删除分组</el-link>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<div v-for="(proc,index) in item.procs" :key="proc.proId" class="text item">
<el-row style="margin-top: 10px;">
<el-col :span="6">
<!--<el-image
style="float: left;"
:src="url"
fit="cover"></el-image>-->
<el-avatar shape="square" size="large" :src="url" style="margin-top: 14px;float: left;"></el-avatar>
<p style="margin-left: 45px;color: #282727;line-height: 36px;font-size: 16px">{{proc.proName}}</p>
</el-col>
<el-col :span="8"><span>
<p style="margin-top: -1px;color: #9B9B9B">权限:</p><div>
谁可以发起:
<span v-if="proc.actionRoleId_dictTexts">
{{proc.actionRoleId_dictTexts|nameFormat}}
</span>
<span v-if="proc.actionUserId_dictTexts">
{{proc.actionUserId_dictTexts|nameFormat}}
</span>
<span v-if="!proc.actionRoleId_dictTexts && !proc.actionUserId_dictTexts">
无
</span>
<el-button
size="mini"
type="text" @click="addFpPermis(proc)">修改</el-button>
</div>
</span>
</el-col>
<el-col :span="4"><p style="margin-top: -1px;color: #9B9B9B">最后更新:</p>
<div>{{proc.lastActionTime}}</div>
</el-col>
<el-col :span="6">
<el-link :underline="false" type="primary" style="margin: 15px 0px 15px 250px " @click="editFp(proc)">
编辑
</el-link>
<el-divider direction="vertical"></el-divider>
<el-link :underline="false" type="primary" @click="groupMove(proc)">移动到</el-link>
<el-divider direction="vertical"></el-divider>
<el-dropdown>
<span class="el-dropdown-link">
<el-link :underline="false" type="primary">数据管理</el-link>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>
<el-link :underline="false" type="primary" @click="actionProcStatus(proc)">{{proc.status ==
'1'?'停用':'发布'}}
</el-link>
</el-dropdown-item>
<el-dropdown-item>
<el-link :underline="false" type="primary" @click="delFp(proc)">删除</el-link>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-col>
</el-row>
<el-divider v-if="index != item.procs.length-1"/>
</div>
</el-card>
</div>
</div>
<div v-if="flag=='2'">
<el-row>
<el-col :span="24">
<el-card class="box-card">
<el-row>
<el-col :span="9">
<el-button style="margin-top: 20px" icon="el-icon-arrow-left" @click="callMainPage">返回</el-button>
<span style="margin-left: 35px;font-size: 18px;font-weight: bold;">{{baseForm.proName}}</span>
</el-col>
<el-col :span="10">
<ul>
<li style="margin-top: 28px;list-style: none;display: inline">1.
<el-link
@click="showTag('base')"
:style="selectFlag=='base'?'font-size: 16px; border-bottom: 1px solid #409EFF;':'font-size: 16px;'">
<p style="margin-top: 14px; margin-right: 14px;">基础设置</p></el-link>
</li>
<li style="margin-top: 28px;list-style: none;display: inline">2.
<el-link
@click="showTag('form')"
:style="selectFlag=='form'?'font-size: 16px; border-bottom: 1px solid #409EFF;':'font-size: 16px;'">
<p style="margin-top: 14px;margin-right: 14px">表单设计</p></el-link>
</li>
<li style="margin-top: 28px;list-style: none;display: inline">3.
<el-link
@click="showTag('proc')"
:style="selectFlag=='proc'?'font-size: 16px; border-bottom: 1px solid #409EFF;':'font-size: 16px;'">
<p style="margin-top: 14px;">流程设计</p></el-link>
</li>
</ul>
</el-col>
<el-col :span="5">
<el-button style="float: right;margin: 25px 2px;" :type="baseForm.status == '1'?'danger':'info'"
@click="actionProcStatus({proName: baseForm.proName, proId: baseForm.proId, status: baseForm.status})">
{{ baseForm.status ==
'1'?'停用':'发布'}}
</el-button>
<el-button style="float: right;margin: 25px 2px;" type="primary" @click="saveDatas">保存</el-button>
<el-button style="float: right;margin: 25px 2px;" @click="showTag('show')">预览</el-button>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<el-row type="flex" class="row-bg" style="margin-top: 10px" v-if="selectFlag=='base'">
<el-col :span="7">
</el-col>
<el-col :span="10">
<el-card class="box-card">
<el-form ref="baseForm" style="margin-top: 60px;margin-bottom: 80px;" :model="baseForm" :rules="baseRules"
label-width="120px">
<!-- <el-form-item label="图标" prop="imageUrl">
<el-upload
class="avatar-uploader"
action="https://jsonplaceholder.typicode.com/posts/"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<img v-if="baseForm.imageUrl" :src="baseForm.imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>-->
<el-form-item label="流程名称" prop="proName">
<el-input
style="width: 520px"
v-model="baseForm.proName"
placeholder="请输入流程名称"/>
</el-form-item>
<el-form-item label="所在分组" prop="proGroup">
<el-select
v-model="baseForm.proGroup"
clearable
style="width: 520px;"
size="small"
placeholder="请选择所在分组">
<el-option
v-for="data in datas"
:key="data.id"
:label="data.groupName"
:value="data.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="流程说明" prop="proDesc">
<el-input
style="width: 520px"
type="textarea"
:rows="4"
v-model="baseForm.proDesc"
placeholder="请输入流程说明"/>
</el-form-item>
</el-form>
</el-card>
</el-col>
<el-col :span="7">
</el-col>
</el-row>
<el-row type="flex" class="row-bg" style="margin-top: 10px" v-if="selectFlag=='form'">
<fg ref="fg"></fg>
</el-row>
<el-row v-if="selectFlag=='proc'">
<el-card class="box-card" style="margin-top: 10px;height: 95vh;">
<el-row style="margin-top: 20px">
<el-alert
title="需要分支可以设置审批条件,可作为审批条件的控件包含:数字输入框、单选框、下拉选择框,且控件需为必填字段"
type="warning"
:closable="false"
show-icon>
</el-alert>
</el-row>
<el-row>
<el-card style="margin-top: 20px;margin-right: 80px;height: 16vh" :border="true" shadow="never">
<div style="margin: 30px 0px">
<div style="float: left; margin: 40px 20px 0px 20px">
<el-popover
placement="right"
width="300"
trigger="click">
<el-row>
<el-col :span="12" v-for="item in nodeTypes">
<el-link :underline="false" @click="actionNode(item.dictValue, '0')">
<el-card shadow="never" class="my-card">
{{item.dictLabel}}
</el-card>
</el-link>
</el-col>
</el-row>
<el-link
slot="reference"
type="primary"
:underline="false"
icon="el-icon-circle-plus"
style="font-size: 14px;">
</el-link>
</el-popover>
</div>
<div style="float: left;" v-for="(nodeData, i) in nodeDatas">
<div style="float: left;margin-top: -15px;" :class="[{'item-card': true, 'item-card-0': nodeData.nodeType == '0', 'item-card-1': nodeData.nodeType == '1', 'item-card': nodeData.nodeType == '2'}]">
<el-card class="box-card" style="width: 150px;">
<div slot="header" class="clearfix" style="height: 8px;font-size: 8px;">
<span>{{nodeData.nodeName}}</span>
<el-link style="float: right; padding: 3px 0" icon="el-icon-close" :underline="false"
type="warning" @click="removeNode(i)"></el-link>
</div>
<div :key="1" class="text item" style="height: 80px;">
<el-link :underline="false" @click="showNodeAction(nodeData, i)">
<p style="display: inline;" v-if="nodeData.nodeType != '2'">{{nodeData |
filterExams}}</p>
<p style="display: inline;" v-if="nodeData.nodeType == '2'">
{{nodeData.fpDefCallBack?nodeData.fpDefCallBack.callbackName:''}}</p>
<i class="el-icon-arrow-right"
style="display: inline;float: right;margin-top: 4px;margin-left: 8px;"></i>
</el-link>
</div>
</el-card>
</div>
<div style="float: left; margin: 40px 20px 0px 20px" v-if="i != nodeDatas.length-1">
<el-popover
placement="right"
width="300"
trigger="click">
<el-row>
<el-col :span="12" v-for="item in nodeTypes">
<el-link :underline="false" @click="actionNode(item.dictValue, (i + 1) + '')">
<el-card shadow="never" class="my-card">
{{item.dictLabel}}
</el-card>
</el-link>
</el-col>
</el-row>
<el-link
slot="reference"
type="primary"
:underline="false"
:style="linkIcon.length > 0 && linkIcon[i + '']?'font-size: 14px; padding-right: 10px;':'font-size: 24px;'">
<i
:class="linkIcon.length > 0 && linkIcon[i + '']?linkIcon[i + '']:'el-icon-caret-right'"
@mouseover="mouseAction(true, i + '')"
@mouseleave="mouseAction(false, i + '')"></i>
</el-link>
</el-popover>
</div>
</div>
<div style="float: left;margin: 12px 20px 0px">
<el-popover
placement="right"
width="300"
trigger="click">
<el-row>
<el-col :span="12" v-for="item in nodeTypes">
<el-link :underline="false" @click="actionNode(item.dictValue, nodeDatas.length)">
<el-card shadow="never" class="my-card">
{{item.dictLabel}}
</el-card>
</el-link>
</el-col>
</el-row>
<el-button
slot="reference"
class="add-node"
icon="el-icon-plus"
style="height:75px;width:75px"
circle></el-button>
</el-popover>
<div style="font-size: 10px;">添加审批节点</div>
</div>
</div>
</el-card>
<el-card v-if="showNode" style="margin-top: 20px;margin-right: 80px;height: 52vh" :border="true"
shadow="never">
<div v-if="nodeType=='0'">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="设置审批人" name="first"/>
<el-tab-pane label="表单操作权限" name="second"/>
</el-tabs>
<div v-if="activeName == 'first'">
<el-row class="radio-row">
<el-radio-group v-model="radio">
<el-radio-button label="成员"></el-radio-button>
<el-radio-button label="角色"></el-radio-button>
</el-radio-group>
</el-row>
<el-row class="radio-row" v-if="radio == '成员'">
<el-button type="primary" icon="el-icon-plus" size="small" @click="addUser">添加成员</el-button>
<p class="row-p">不能超过20人</p>
<div v-if="nodeDatas[currentNode].fpDefExams.length > 0" style="margin-top: 5px;">
<el-tag v-for="fde in nodeDatas[currentNode].fpDefExams" v-if="fde.userNameDictText" size="mini"
closable>{{fde.userNameDictText}}
</el-tag>
</div>
</el-row>
<el-row class="radio-row" v-else>
<el-button type="primary" icon="el-icon-plus" size="small" @click="addUser">添加角色</el-button>
<p class="row-p">点击添加审批角色</p>
<div v-if="nodeDatas[currentNode].fpDefExams.length > 0" style="margin-top: 5px;">
<el-tag v-for="fde in nodeDatas[currentNode].fpDefExams" v-if="fde.roleNameDictText" size="mini"
closable>{{fde.roleNameDictText}}
</el-tag>
</div>
</el-row>
<el-divider/>
<el-row class="radio-row">
<p class="empty-p">审批人为空时</p>
<el-radio-group v-model="emptyType" @change="emptyTypeChange">
<el-radio :label="0">自动通过</el-radio>
<el-radio :label="1">自动拒绝</el-radio>
<!-- <el-radio :label="2">指定成员</el-radio>-->
</el-radio-group>
</el-row>
</div>
<div v-else class="serve-form">
<el-row class="radio-row">
<p class="empty-p">节点操作</p>
<el-checkbox-group
@change="nodeActionTypeChange"
v-model="nodeActionType">
<el-checkbox v-for="dict in nodeActionTypes" :disabled="dict.dictValue == '0'"
:label="dict.dictValue" :key="dict.dictValue">{{dict.dictLabel}}
</el-checkbox>
</el-checkbox-group>
</el-row>
<el-divider/>
<el-row class="radio-row">
<p class="empty-p">节点权限</p>
<p style="display: inline;font-size: 10px;">表单字段:</p>
<el-checkbox :value="true" disabled>只读</el-checkbox>
</el-row>
<el-row class="radio-row"
v-if="nodeDatas[currentNode].nodeAction.indexOf('3') == -1 && nodeDatas[currentNode].nodeSort != nodeDatas.filter(o => o.nodeSort == '0')[0].nodeSort">
<p style="display: inline;font-size: 10px;">标记为:</p>
<el-radio-group @change="markedAsChange" v-model="markedAs">
<el-radio :label="0">普通节点</el-radio>
<el-radio :label="1">处理异议节点</el-radio>
</el-radio-group>
</el-row>
<el-divider/>
<el-row class="radio-row">
<p class="empty-p">节点描述</p>
<el-input
type="textarea"
:rows="2"
placeholder="请输入节点描述"
v-model="nodeDatas[currentNode].remark">
</el-input>
</el-row>
</div>
</div>
<div v-if="nodeType=='1'">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="设置抄送人" name="first"/>
<el-tab-pane label="表单操作权限" name="second"/>
</el-tabs>
<div v-if="activeName == 'first'">
<el-row class="radio-row">
<el-radio-group v-model="radio" v-if="activeName == 'first'">
<el-radio-button label="成员"></el-radio-button>
<el-radio-button label="角色"></el-radio-button>
</el-radio-group>
</el-row>
<el-row class="radio-row" v-if="radio == '成员'">
<el-button type="primary" icon="el-icon-plus" size="small" @click="addUser({nodeType: '1'})">添加成员
</el-button>
<p class="row-p">不能超过20人</p>
</el-row>
<el-row class="radio-row" v-else>
<el-button type="primary" icon="el-icon-plus" size="small" @click="addUser({nodeType: '1'})">添加角色
</el-button>
<p class="row-p">点击添加审批角色</p>
</el-row>
</div>
<div v-else class="serve-form">
<el-row class="radio-row">
<p class="empty-p">节点权限</p>
<p style="display: inline;font-size: 10px;">表单字段:</p>
<el-checkbox :value="true" disabled>只读</el-checkbox>
</el-row>
<el-divider/>
<el-row class="radio-row">
<p class="empty-p">节点描述</p>
<el-input
type="textarea"
:rows="2"
placeholder="请输入节点描述"
v-model="nodeDatas[currentNode].remark">
</el-input>
</el-row>
</div>
</div>
<div v-if="nodeType=='2'">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="普通模式" name="first"/>
</el-tabs>
<el-form ref="serveForm" :model="serveForm" :rules="serveRules" label-width="160px" class="serve-form">
<el-form-item label="表达式" prop="javaBean">
<el-select
v-model="serveForm.javaBean"
clearable
size="small"
@change="setFpCallBacks"
placeholder="请选择表达式">
<el-option
v-for="dict in javaBeans"
:key="dict.javaBean"
:label="dict.callbackName"
:value="dict.javaBean"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="节点描述" prop="remark">
<el-input
type="textarea"
:rows="2"
placeholder="请输入节点描述"
v-model="nodeDatas[currentNode].remark">
</el-input>
</el-form-item>
</el-form>
</div>
<div style="text-align:left;margin-top: 50px;margin-left: 100px;">
<el-button type="primary" @click="submitNodeForm">确 定</el-button>
<el-button>取 消</el-button>
</div>
</el-card>
</el-row>
</el-card>
</el-row>
<el-row type="flex" class="row-bg" style="margin-top: 10px" v-if="selectFlag=='show'">
<el-col :span="24">
<el-card class="fp-card" v-if="activities.length > 0">
<div slot="header" class="clearfix">
<span>预览流程样式</span>
</div>
<div class="text" style="margin-top: 18px;">
<el-timeline>
<el-timeline-item
v-for="(activity, index) in activities"
:key="index"
:type="activity.status=='1'?'primary':''"
:timestamp="activity.timestamp">
<p style="font-size: 18px;">{{activity.title}}</p>
<p style="color: #909399;"> {{activity.approver}}</p>
<p v-if="activity.remark" style="display: inline;font-size: 16px;">描述:</p>
<p style="display: inline;">{{activity.remark}}</p>
</el-timeline-item>
</el-timeline>
</div>
</el-card>
<el-card class="fp-card" v-else>
<el-empty description="请先设计流程!"></el-empty>
</el-card>
</el-col>
</el-row>
</div>
<!-- 添加或修改流程分组对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="组名" prop="groupName">
<el-input v-model="form.groupName" placeholder="请输入组名"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
<!--分组重命名-->
<el-dialog title="分组重命名" :visible.sync="opengroup" width="680px" append-to-body>
<el-form ref="formgroup" :model="formgroup" :rules="rulegroups" label-width="120px" class="action-form">
<el-form-item label="新的分组名称" prop="groupName">
<el-input v-model="formgroup.groupName" placeholder="请输入新的分组名称"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="subData">确 定</el-button>
<el-button @click="cancelgroup">取 消</el-button>
</div>
</el-dialog>
<!--移动到分组-->
<el-dialog title="移动到分组" :visible.sync="openMove" width="680px" append-to-body>
<el-form ref="formMove" :model="formMove" :rules="ruleMoves" label-width="120px" class="action-form">
<el-form-item label="分组名称" prop="proGroup">
<el-select
v-model="formMove.proGroup"
clearable
style="width: 520px;"
size="small"
placeholder="请选择分组">
<el-option
v-for="data in datas"
:key="data.id"
:label="data.groupName"
:value="data.id"
></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="subMove">确 定</el-button>
<el-button @click="cancelMove">取 消</el-button>
</div>
</el-dialog>
<user-form ref="userForm" @setUserVal="setUserVal"></user-form>
<permis-form ref="permisForm" @getList="getList"></permis-form>
</div>
</template>
<script>
import { addProce, delProce, getProce, queryPs, setStatus, updateProce } from '@/api/fp/proce'
import { allCallback, insertNode, listNodeDatas } from '@/api/fp/node'
import { addGroup, allGroup, delGroup, sortGroup, updateGroup } from '@/api/fp/group'
import fg from './fg/index'
import UserForm from './form/UserForm'
import PermisForm from './form/PermisForm'
import { removeDrawingList, removeFormConf, saveDrawingList, saveFormConf } from '@/utils/db'
export default {
name: 'Proce',
components: { fg, UserForm, PermisForm },
data() {
return {
url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAGgElEQVR4Xu2beXDNVxTHP79EQixFpESYNragtpZExdCOpRRtTSqYRlOtQUvRTFFT+odpTTvVIjOUGVWjllYZW221pLRqp5bIlFoSQSVMSMSSIHmdkyveE0neu7/3exlZzkwm80vOueec7+/ec84993cNClDgTFsrmxfDDXgFeAaoUZCnlD1nAsk22GbksiDlYyPB0X7j4cNUm29gLWbYYJQB3qXMSZfMtUGOAfNS0hnPVOOuCCkAxPnabMJGD5dGKu1MBnEp1+krIOQBEBhrmw2MKe1+ado/JyXGGGs8WPPHyuq0LwqUvOWQSzujXqxtlgExmuiVCXYbxBqBsbYTQKsy4ZG+EwkCwI0ykOr0XVcSmQKAzax0WZCrAKBiBlQsgZKJAXX8oH8I9GoETWrD01UhKwcuZMC+/2DVSTiaWvJRxeMxoJIXjAuFUR2gum/xDu5Igik7ITGj5IDwKAD+VWBBPwhv6LpDN7Lhg82w47zrMu5wegyAyt6wJhJeCNQ3L/s+vLUW9l7Sl9WV8BgAX3eHd9rommPnT7kJ3ZZBepb5MVyR9AgAzetAXBR4e7liQtE8cw/DF3+5N4YzaY8A8G0PGNLamWrn/795F9p8D1n3nfOa5bAcAHnpR0eoNGcFDf0VtiZaMVLhY1gOQMMacHCYdQbP2Aff7rduvIIjWQ5Ah0DYMNg6g5eegIlx1o3ncQA6BsG6gdYZvOwETChNADSqCXvetQ6AUrcEpMua8D7UrmINCNHrYHuSNWMVNorlMUCUzOgJURY02aQsfn4B3ClNaVAAaBUAW6PAy37sYuoVltpCSLyd3h2i3SiFU2/CS0vgRt75jefII0tAzK1SSWWDtnX1jZfN0MDVcPCyvqyuhMcAEENqVYYl/SG0vutmybofsRH+vOC6jDucHgVADJOGyEdhMKo9VHPSEIlLgsk7IFka9SVEHgcg3w9pjkQ0hx6NoEUdqFkZ7ubA+Qy17199EuKvlpDXDmo8DoBfJahfXf1Ik8Qw1JG0/JaN0z2b2vOfvgaZhQQ8kalXDXy94eptyMi2FiSPACAGD2wJrzZWHSFn6TAzGwavgSMPmqJVfVQdITOmTV3wcegrpN6C7YmwOB6OX3EfDEsBqOELY8NgeDvw83HNOIn4kavgUIri79MEvuqm3npxJL3sdf/CpN/dS5WWAdDMH358HRrVcs3xfK7Pd8G8v9VTTBh8Eq6Wh6t09jpErTUfOC0B4MUgle5kBujQsVTo+wvk2iC6NUw3+X3KqTR4bQVIB0mX3AYguCZsHAz+frqqVb7fcAaerQk731bFk1ladBw+3aEv7RYA3gZsi4KWAfqKpesbuhBybDC7F0S21B/DUeJeLnRdrNKqDrkFwHtt4ctuOursvCv/gXFbQdJkwkjXg6aMcOWWCn5Na8OULvYxp++FWQf07DENgEzXw8PMTX0xccJ2WJYAPYNV/HCVLmXCoNVwLh0C/CB+pF3y8GUVC3TINAARITC3j46qR3klcsvxV8FZlJgOabchNOjxsZPS1SbpYiY85QtL+0OYA9/VW9B2gZ5NpgGY0xsGtNBT5sjdd7kqfCT1Teps/0/r+ZB2ByaFQ0xH+98l0kuxJIWQlNU/Rzy+08zOgeA5ejaZBuCPaAjx11PmyD1gFey5+Hj6G78dfnrwMeuYUJjcGeKvqLPCa1mqQFoRASF1Htd9ORPaL9SzyTQAZ0Y5390VZ8qHv8HqU9C5AayKtHNKTSDpTEpdoTeaqaUi+wQ5c1j5JgQXUWztSoZBa0oIgOQx4OPGF8XfHYJpu0FS6fERjwZTKXPlTDC/QhSXGtdSzgcV8+n2Zzvhh2MlBEDcEHjORP7PN+9kGnRbqp5kmsseoiDN3A/f7FN6lkcUf9wmjZTwRWqZ6JDpJRDZAmb31lH1KK+85e7LQICQiL57KAQUcp6YnKHWfWUnVaLMGGmi6pJpAETR6A4wsZP5Enb9aRi5SZncqYEKbmaW1ZZzMGw95Op6L30Jdz+Tk75f+0CQPbwuScDbfBbyv9Ts3RgkvTr7lshRz5azMHoL3L6nq13xuw2AObVFS0lqnfYydJW7KsWQdJFiD8D8I3YAzdjyxAGQ74QcsvZrCl0aqnaaNFikJSYF0bZE1Qyxoj32xAJg5m2akakAwN0gaAb1J0mmYgZUXJgo71dmKi5Nqauy5ffanETkcn1xMi8llfersw9BKLeXpx0qk/J2ff5/0SNYsfy1VQMAAAAASUVORK5CYII=',
imageUrl: '',
// 遮罩层
loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 提示
pvisible: false,
showNode: false,
// 总条数
total: 0,
// 表格数据
datas: [],
// 节点数据
nodeDatas: [],
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
opengroup: false,
openMove: false,
// 查询参数
queryParams: {
proName: null
},
// 表单参数
form: {
groupSort: null,
groupName: null
},
formgroup: {},
// 基础设置参数
baseForm: {},
// 移动到
formMove: {},
// 服务节点设置参数
serveForm: {},
// 表单校验
ruleMoves: { proGroup: [{ required: true, message: '分组不能为空', trigger: 'blur' }] },
rulegroups: {
groupName: [{ required: true, message: '分组名称不能为空', trigger: 'blur' }]
},
rules: {
groupName: [
{ required: true, message: '流程名称不能为空', trigger: 'blur' }
]
},
// 基础设置参数校验
baseRules: {
proName: [
{ required: true, message: '流程名称不能为空', trigger: 'blur' }
],
proGroup: [
{ required: true, message: '流程分组不能为空', trigger: 'blur' }
],
imageUrl: [
{ required: false, message: '图标不能为空', trigger: 'blur' }
]
},
// 服务节点参数校验
serveRules: {
javaBean: [
{ required: true, message: '表达式不能为空', trigger: 'blur' }
]
},
userId: [],
roleId: [],
flag: '1',
selectFlag: 'base',
activeName: 'first',
radio: '成员',
emptyType: 0,
nodeType: '',
actionType: '',
markedAs: 0,//标记为
linkIcon: [],
currentNode: '0',//当前操作节点
nodeActionType: ['0', '1'],
javaBeans: [],//表达式字典数据
nodeTypes: [],//节点类型字典数据
nodeActionTypes: [],//节点操作类型字典数据
activities: []
}
},
created() {
this.getList()
this.initDictConfig()
},
filters: {
nameFormat(dictTexts) {
let text = ''
dictTexts.map(item => text += item + ',')
return text.substring(0, text.length - 1)
},
filterExams(data) {
let text = ''
data.fpDefExams.map(item => {
if (item.roleNameDictText) {
text += item.roleNameDictText + ','
}
if (item.userNameDictText) {
text += item.userNameDictText + ','
}
})
return text ? text.substring(0, text.length - 1) : data.nodeType == '0' ? '添加审批人' : data.nodeType == '1' ? '添加抄送人' : ''
}
},
methods: {
/**基本字典类型数据初始化*/
initDictConfig() {
allCallback('fp_java_bean').then(response => {
this.javaBeans = response.data
})
this.getDicts('fp_node_type').then(response => {
this.nodeTypes = response.data
})
this.getDicts('fp_node_action_type').then(response => {
this.nodeActionTypes = response.data
})
},
/** 查询流程定义列表 */
getList() {
this.loading = true
allGroup(this.queryParams).then(response => {
this.datas = response.data
this.loading = false
})
},
// 取消按钮
cancel() {
this.open = false
this.reset()
},
// 表单重置
reset() {
this.form = {
proId: null,
status: '0',
proName: null,
proGroup: null,
groupSort: 1
}
this.resetForm('form')
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm')
this.handleQuery()
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.proId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = '新建分组'
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const proId = row.proId || this.ids
getProce(proId).then(response => {
this.form = response.data
this.open = true
this.title = '修改流程定义'
})
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate(valid => {
if (valid) {
if (this.form.proId != null) {
updateGroup(this.form).then(response => {
this.msgSuccess('修改成功')
this.open = false
this.getList()
})
} else {
addGroup(this.form).then(response => {
this.msgSuccess('新增成功')
this.open = false
this.getList()
})
}
}
})
},
handleAvatarSuccess(res, file) {
this.imageUrl = URL.createObjectURL(file.raw)
},
beforeAvatarUpload(file) {
const isPNG = file.type === 'image/png'
const isLt2M = file.size / 1024 / 1024 < 2
if (!isPNG) {
this.$message.error('上传头像图片只能是 png 格式!')
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!')
}
return isJPG && isLt2M
},
handleClick(tab, event) {
console.log(tab, event)
},
showNodeAction(nodeData, i) {
this.nodeType = nodeData.nodeType
this.currentNode = i
this.actionType = 'edit'
let userId = []
let roleId = []
nodeData.fpDefExams.length > 0 ? nodeData.fpDefExams.map(item => {
userId = item.userId ? [...userId, Number(item.userId)] : []
roleId = item.roleId ? [...roleId, Number(item.roleId)] : []
this.emptyType = Number(item.emptyType)
}) : this.emptyType = 0
this.serveForm.javaBean = nodeData.fpDefCallBack ? nodeData.fpDefCallBack.javaBean : null
this.userId = userId
this.roleId = roleId
this.radio = roleId.length > 0 ? '角色' : '成员'
this.nodeActionType = [...nodeData.nodeAction.split(',')]
this.markedAs = Number(nodeData.markedAs)
this.activeName = 'first'
this.showNode = true
},
actionNode(nodeType, currentNode) {
this.nodeType = nodeType
this.currentNode = currentNode
this.actionType = 'add'
this.value = []
this.emptyType = 0
this.nodeActionType = ['0', '1']
this.markedAs = '0'
this.serveForm.javaBean = null
let nodeData = {
nodeId: '',
nodeSort: '2',
nodeName: nodeType == '0' ? '审批人' : nodeType == '1' ? '抄送人' : '服务节点',
nodeType: nodeType,
signCode: '',
callbackId: '',
fpDefCallBack: null,
nodeAction: '0,1',
nodePermis: '0',
markedAs: '0',
fpDefExams: []
}
this.nodeDatas.splice(currentNode, 0, nodeData)
let index = 0
this.nodeDatas.map(item => {
item.nodeSort = index + ''
index++
})
this.activeName = 'first'
this.showNode = true
},
removeNode(i){
this.nodeDatas = this.nodeDatas.filter(item => item.nodeSort != i)
let index = 0
this.nodeDatas.map(item => {
item.nodeSort = index + ''
index++
})
},
submitNodeForm() {
this.showNode = false
},
mouseAction(flag, i) {
this.linkIcon = []
if (flag) this.linkIcon[i] = 'el-icon-circle-plus'
},
/*创建流程*/
createFp() {
this.flag = '2'
},
/*修改流程*/
editFp(row) {
this.flag = '2'
this.baseForm = { ...row }
},
/*返回主页面*/
callMainPage() {
this.flag = '1'
this.selectFlag = 'base'
this.baseForm = {}
this.showNode = false
this.getList()
},
/*保存数据*/
saveDatas() {
if (this.selectFlag == 'base') {
this.$refs['baseForm'].validate(valid => {
if (valid) {
if (this.baseForm.proId) {
updateProce({ ...this.baseForm }).then(res => {
this.baseForm.status = '0'
this.msgSuccess('修改成功!')
this.getList()
})
} else if (!this.baseForm.proId) {
addProce({ ...this.baseForm }).then(res => {
this.baseForm.status = '0'
this.baseForm.proId = res.msg
this.msgSuccess('创建成功!')
this.getList()
})
}
}
})
}
if (this.selectFlag == 'form') {
this.baseForm.formJson = JSON.stringify(this.$refs.fg.getJson())
updateProce({ ...this.baseForm }).then(response => {
this.msgSuccess('操作成功!')
this.getList()
})
}
if (this.selectFlag == 'proc') {
let thiz = this
this.$confirm('是否确认保存' + thiz.baseForm.proName + '?,更改节点可能会导致已存在的流程无法使用!', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
insertNode({ nodeDatas: thiz.nodeDatas, proId: thiz.baseForm.proId }).then(res => {
thiz.msgSuccess('操作成功!')
thiz.listNodeData()
})
}).catch(() => {
})
}
},
showTag(flag) {
if ((flag == 'show' && this.selectFlag == 'show') || flag == 'proc') {
flag = 'proc'
if (this.baseForm.proId) {
this.showNode = false
this.selectFlag = flag
this.listNodeData()
} else {
this.msgError('请先保存基础参数设置!')
}
}
if (flag == 'form') {
if (this.baseForm.proId) {
removeDrawingList()
removeFormConf()
let formJson = JSON.parse(this.baseForm.formJson)
let drawingList = []
formJson && formJson.fields.length > 0 ? formJson.fields.map(fileds => {
drawingList = [...drawingList, { __config__: fileds.__config__ }]
}) : ''
saveDrawingList(drawingList)
saveFormConf(formJson)
this.selectFlag = flag
} else {
this.msgError('请先保存基础参数设置!')
}
}
if (flag == 'base') {
this.selectFlag = flag
}
if (this.selectFlag != 'show' && flag == 'show') {
this.activities = []
this.selectFlag = flag
this.baseForm.proId ? queryPs({ proId: this.baseForm.proId }).then(res => {
if (res.data) {
this.activities = res.data
}
}) : ''
}
},
listNodeData() {
listNodeDatas(this.baseForm.proId).then(res => {
this.nodeDatas = res.data
})
},
/*添加成员*/
addUser(row) {
row.value = this.radio == '成员' ? this.userId : this.roleId
row.flag = this.radio == '成员' ? '1' : '2'
row.currentNode = this.currentNode
row.actionType = this.actionType
row.nodeType = this.nodeType
row.emptyType = this.emptyType
this.$refs.userForm.show(row)
},
setUserVal(val) {
this.nodeDatas[val.currentNode].fpDefExams = val.fpDefExams
},
emptyTypeChange(val) {
this.emptyType = val
this.nodeDatas[this.currentNode].fpDefExams.map(item => item.emptyType = val)
},
nodeActionTypeChange(val) {
let nodeAction = ''
val.map(item => {
nodeAction += item + ','
})
this.nodeDatas[this.currentNode].nodeAction = nodeAction.substring(0, nodeAction.length - 1)
},
markedAsChange(val) {
this.nodeDatas[this.currentNode].markedAs = val
},
setFpCallBacks() {
this.nodeDatas[this.currentNode].fpDefCallBack = {
callbackName: this.javaBeans.filter(item => item.javaBean == this.serveForm.javaBean)[0].callbackName,
javaBean: this.serveForm.javaBean,
callbackStatus: '1'
}
},
cancelgroup() {
this.formgroup = {}
},
reName(item) {
this.opengroup = true
this.formgroup.id = item.id
},
subData() {
this.$refs['formgroup'].validate(valid => {
if (valid) {
updateGroup({ ...this.formgroup }).then(res => {
this.msgSuccess('操作成功!')
this.opengroup = false
this.getList()
})
}
})
},
/** 删除流程*/
delFp(row) {
let thiz = this
this.$confirm('是否确认删除' + row.proName + '?,删除可能会导致已存在的流程消失!', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delProce(row.proId).then(res => {
thiz.msgSuccess('操作成功!')
thiz.getList()
})
}).catch(() => {
})
},
actionProcStatus(row) {
let thiz = this
let title = ''
let param = {
proId: row.proId
}
if (row.status == '1') {
param.status = '0'
title = '是否确认停用' + row.proName + '?,停用可能会导致已存在的流程无法再进行!'
} else if (row.status == '0') {
param.status = '1'
title = '是否确认发布' + row.proName + '?'
}
this.$confirm(title, '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
setStatus(param).then(res => {
if (thiz.flag == '2') thiz.baseForm.status = param.status
thiz.msgSuccess('操作成功!')
thiz.getList()
})
}).catch(() => {
})
},
/*删除分组*/
delGroupData(row) {
let thiz = this
this.$confirm('是否确认删除分组' + row.groupName + '?,删除分组也会删除分组中的流程,可能导致已存在的流程无法再进行!', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delGroup(row.id).then(res => {
thiz.msgSuccess('操作成功!')
thiz.getList()
})
}).catch(() => {
})
},
/*移动到*/
subMove() {
let thiz = this
this.$refs['formMove'].validate(valid => {
if (valid) {
this.$confirm('是否确认将' + this.formMove.item.proName + '移动到所选择的分组!', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
updateProce({ proId: this.formMove.item.proId, proGroup: this.formMove.proGroup }).then(res => {
thiz.msgSuccess('操作成功!')
thiz.getList()
thiz.cancelMove()
})
}).catch(() => {
})
}
})
},
groupMove(item) {
this.formMove.item = item
this.openMove = true
},
cancelMove() {
this.formMove = {}
this.openMove = false
},
/*分组排序*/
orderGroup(flag, row, index) {
if (this.datas && this.datas.length > 1) {
let params = []
let data = null
/*向上移动*/
if (flag && index > 0) {
data = this.datas[index - 1]
}
/*向下移动*/
if (!flag && index < this.datas.length - 1) {
data = this.datas[index + 1]
}
if (data) {
params = [{
id: data.id,
groupSort: row.groupSort
}, {
id: row.id,
groupSort: data.groupSort
}]
sortGroup({ gpvs: params }).then(res => {
this.getList()
})
}
}
},
/*设置流程权限*/
addFpPermis(item) {
this.$refs.permisForm.show(item)
}
}
}
</script>
<style>
.text {
font-size: 13px;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
body {
background-color: #f8fafc
}
.el-card__body {
padding: 0px 20px 0px 20px;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 64px;
height: 64px;
line-height: 64px;
text-align: center;
}
.avatar {
width: 64px;
height: 64px;
display: block;
}
.base-link {
width: 64px;
height: 1px;
background: #1890FF;
bottom: 0;
transition: left ease-in-out 0.5s;
}
.el-alert--warning.is-light {
background-color: #ffffff;
}
.el-alert__title {
color: rgba(0, 0, 0, 0.65);
}
.add-node {
border: 1px dashed #E3E3E3;
}
.add-node:hover {
border: 1px dashed #1890FF;
}
.add-node .el-icon-plus {
font-size: 30px;
color: #E3E3E3;
}
.add-node .el-icon-plus:hover {
font-size: 30px;
color: #1890FF;
}
.item-card .el-card__header {
padding: 14px 15px 7px;
min-height: 40px;
background-color: #ccb1ea;
}
.item-card-0 .el-card__header {
background-color: #13ce66;
}
.item-card-1 .el-card__header {
background-color: #e6a23c;
}
.item-card .el-card__body {
padding: 8px;
}
.my-card {
margin: 5px;
width: 125px;
height: 25px;
text-align: center;
line-height: 25px;
}
.radio-row {
margin-bottom: 20px;
}
.row-p {
font-size: 10px;
color: rgba(51, 42, 42, 0.45);
margin-left: 8px;
display: inline;
}
.empty-p {
font-size: 14px;
color: rgba(0, 0, 0, 0.85);
margin-top: 0;
margin-bottom: 1em;
}
.serve-form .el-select {
width: 410px;
text-align: center;
}
.serve-form .el-textarea {
width: 410px;
text-align: center;
}
</style>
- start —> index.vue
<template>
<div class="app-container" :style="flag == '1'?'':'background-color: #f0f2f5;'">
<!--我的待办-->
<div v-if="flag == '1'">
<p style="font-size: 18px; font-weight: bold;">待我处理</p>
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="所属流程" prop="proId">
<el-input
v-model="queryParams.proId"
placeholder="请输入所属流程"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="流程发起人" prop="proOriginator" label-width="89px">
<el-input
v-model="queryParams.proOriginator"
placeholder="请输入流程发起人"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="发起时间" prop="subTime">
<el-input
v-model="queryParams.subTime"
placeholder="请输入发起时间"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="startList" border>
<el-table-column label="发起人" align="center" prop="proOriginatorDictText"/>
<el-table-column label="流程" align="center" prop="proName">
<template slot-scope="scope">
<el-link :underline="false" type="primary" @click="openFpDesc(scope.row)">{{scope.row.proName}}</el-link>
</template>
</el-table-column>
<el-table-column label="发起时间" align="center" prop="subTime"/>
<el-table-column label="所属业务类型" align="center" prop="busType">
<template slot-scope="scope">
<el-tag>一般业务</el-tag>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
<!--审批详情-->
<div v-if="flag == '2'">
<el-row>
<el-col :span="24">
<el-card shadow="never" style="height: 62px;padding-top: 8px;">
<el-row>
<el-col :span="9">
<el-button style="margin-top: -16px;" icon="el-icon-arrow-left" @click="callMainPage">返回</el-button>
</el-col>
<el-col :span="10">
<p style="display: inline;">{{actionRow.groupName}}</p>
</el-col>
<el-col :span="5" style="margin-top: -10px;">
<div style="float: right;margin-right: -4%;">
<el-button style="margin-right: -2%" type="warning"
v-if="actionRow.nodeActionType.indexOf('3') != -1" @click="openForm('3')">异议
</el-button>
<el-button style="margin-right: -2%" type="success"
v-if="actionRow.nodeActionType.indexOf('2') != -1">转交
</el-button>
<el-button style="margin-right: -2%" type="primary" v-if="actionRow.nodeActionType.indexOf('0') != -1"
@click="openForm('1')">同意
</el-button>
<el-button style="margin-right: -2%" v-if="actionRow.nodeActionType.indexOf('1') != -1" type="danger"
@click="openForm('2')">驳回
</el-button>
</div>
</el-col>
</el-row>
</el-card>
<el-card shadow="never">
<el-row type="flex">
<el-col :span="20" style="margin-right: 40px;">
<parser :form-conf="formConf"></parser>
</el-col>
<el-col :span="2">
<p style="font-size: 13px;color: #909399;">状态</p>
<el-tag color="#f8eaec" v-if="actionRow.proGoStatus == '5'">已转交</el-tag>
<el-tag type="info" v-if="actionRow.proGoStatus == '4'">已撤回</el-tag>
<el-tag type="danger" v-if="actionRow.proGoStatus == '3'">已驳回</el-tag>
<el-tag type="success" v-if="actionRow.proGoStatus == '2'">已完成</el-tag>
<el-tag type="warning" v-if="actionRow.proGoStatus == '1'">审批中</el-tag>
<el-tag v-if="actionRow.proGoStatus == '0'">未审批</el-tag>
</el-col>
<el-col :span="2">
<p style="font-size: 13px;color: #909399;">提交时间</p>
<p style="font-size: 13px;">{{actionRow.subTime}}</p>
</el-col>
</el-row>
</el-card>
<el-card class="fp-card">
<div slot="header" class="clearfix">
<span>流程进度</span>
</div>
<div class="text item">
<fp-time-line ref="ftl" :activities="activities"></fp-time-line>
</div>
</el-card>
</el-col>
</el-row>
</div>
<el-dialog :title="title" :visible.sync="open" width="720px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="10px" class="action-form">
<el-form-item label="" prop="remark">
<el-input type="textarea" :rows="8" v-model="form.remark" placeholder="请输入审批意见!"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="subData">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import Parser from 'form-gen-parser'
import { listStart, executorFp } from '@/api/fp/start'
import { listPs } from '@/api/fp/node'
import FpTimeLine from '../model/tl/index'
export default {
name: 'Start',
components: { Parser, FpTimeLine },
data() {
return {
// 遮罩层
loading: true,
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 是否打开弹窗
open: false,
// 显示搜索条件
showSearch: true,
// 弹窗标题
title: '审批意见',
// 总条数
total: 0,
// 流程启动信息表格数据
startList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
proId: null,
proOriginator: null,
subTime: null
},
flag: '1',
actionRow: {},
formConf: {},
activities: [],
form: { remark: '' },
setForm: { zf: 0 },
rules: {},
formData: {},
selectRow: [],
taskId: ''
}
},
created() {
this.getList()
},
methods: {
/** 查询流程启动信息列表 */
getList() {
this.loading = true
listStart(this.queryParams).then(response => {
this.startList = response.rows
this.total = response.total
this.loading = false
})
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm')
this.handleQuery()
},
callMainPage() {
this.flag = '1'
this.actionRow = {}
this.activities = []
},
/** 打开审批详情*/
openFpDesc(row) {
this.actionRow = row
this.formData = JSON.parse(row.formData)
//回显数据
this.formConf = JSON.parse(row.formConf)
this.callShowData()
this.flag = '2'
this.queryProcessSchedule()
},
queryProcessSchedule() {
listPs({ startId: this.actionRow.id }).then(res => {
if (res.data) {
this.activities = res.data
}
})
},
callShowData() {
this.formConf.fields.map(item => {
var __config__ = item.__config__
__config__.defaultValue = this.formData[item.__vModel__] ? this.formData[item.__vModel__] : __config__.defaultValue
return item
})
},
subData() {
executorFp({
nodeId: this.actionRow.todoNodeId,
startId: this.actionRow.id,
nodeStatus: this.form.type,
remark: this.form.remark
}).then(res => {
this.open = false
this.msgSuccess('操作成功!')
this.getList()
this.callMainPage()
})
},
openForm(flag) {
this.open = true
this.form = {}
this.form.type = flag
},
cancel() {
this.open = false
this.form.type = undefined
}
}
}
</script>
<style scoped lang="scss">
.text {
font-size: 13px;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
.fp-card {
margin-top: 10px;
}
.action-form {
.el-input {
width: 660px
}
.el-textarea {
width: 660px
}
.el-select {
width: 660px;
}
}
</style>
添加菜单
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2163, '流程设计', 2161, 1, 'proce', 'fp/proce/index', 1, 0, 'C', '0', '0', 'fp:proce:list', 'button', 'admin', TIMESTAMP '2021-09-28 18:00:50', 'admin', TIMESTAMP '2021-09-28 18:01:17', null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2191, '我的申请', 2161, 3, 'apply', 'fp/apply/index', 1, 1, 'C', '0', '0', 'fp:start:list', 'select', 'admin', TIMESTAMP '2021-10-12 16:59:59', 'admin', TIMESTAMP '2021-10-12 17:00:39', null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2196, '查询节点', 2190, 1, null, null, 1, 0, 'F', '0', '0', 'fp:busNode:query', '#', 'tj', TIMESTAMP '2021-10-19 16:08:51', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2197, '处理流程', 2190, 2, null, null, 1, 0, 'F', '0', '0', 'fp:start:executorFp', '#', 'tj', TIMESTAMP '2021-10-19 16:16:42', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2198, '查询抄送我的', 2195, 1, null, null, 1, 0, 'F', '0', '0', 'fp:start:ccme', '#', 'tj', TIMESTAMP '2021-10-19 16:28:32', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2199, '查询单个', 2194, 1, null, null, 1, 0, 'F', '0', '0', 'fp:mount:query', '#', 'tj', TIMESTAMP '2021-10-19 16:29:30', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2200, '新增', 2194, 2, null, null, 1, 0, 'F', '0', '0', 'fp:mount:add', '#', 'tj', TIMESTAMP '2021-10-19 16:29:51', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2201, '修改', 2194, 3, null, null, 1, 0, 'F', '0', '0', 'fp:mount:edit', '#', 'tj', TIMESTAMP '2021-10-19 16:30:08', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2202, '删除', 2194, 4, null, null, 1, 0, 'F', '0', '0', 'fp:mount:remove', '#', 'tj', TIMESTAMP '2021-10-19 16:30:28', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2204, '撤回', 2191, 2, null, null, 1, 0, 'F', '0', '0', 'fp:start:initiateFp', '#', 'admin', TIMESTAMP '2021-10-19 16:34:04', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2323, '开启流程', 2009, 26, null, null, 1, 0, 'F', '0', '0', 'fp:start:startFp', '#', 'tangjing', TIMESTAMP '2021-10-25 16:25:36', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2331, '查询流程', 2194, 5, null, null, 1, 0, 'F', '0', '0', 'fp:proce:all', '#', 'tangjing', TIMESTAMP '2021-10-25 16:40:51', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2402, '提交', 2191, 3, null, null, 1, 0, 'F', '0', '0', 'fp:start:rejectedFp', '#', 'tangjing', TIMESTAMP '2021-11-19 14:02:08', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2194, '流程挂载', 2161, 4, 'mount', 'fp/mount/index', 1, 1, 'C', '0', '0', 'fp:mount:list', 'swagger', 'admin', TIMESTAMP '2021-10-15 13:36:41', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2195, '抄送我的', 2161, 5, 'ccme', 'fp/ccme/index', 1, 1, 'C', '0', '0', 'fp:start:query', 'form', 'admin', TIMESTAMP '2021-10-18 13:10:51', 'admin', TIMESTAMP '2021-10-18 13:12:33', null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2203, '查询流程节点数据', 2191, 1, null, null, 1, 0, 'F', '0', '0', 'fp:busNode:query', '#', 'admin', TIMESTAMP '2021-10-19 16:33:09', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2205, '查询流程回调处理列表', 2163, 1, null, null, 1, 0, 'F', '0', '0', 'fp:callback:all', '#', 'admin', TIMESTAMP '2021-10-19 16:42:50', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2206, '查询流程分组列表', 2163, 2, null, null, 1, 0, 'F', '0', '0', 'fp:group:all', '#', 'admin', TIMESTAMP '2021-10-19 16:43:11', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2207, '新增流程分组', 2163, 3, null, null, 1, 0, 'F', '0', '0', 'fp:group:add', '#', 'admin', TIMESTAMP '2021-10-19 16:43:32', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2208, '修改流程分组', 2163, 4, null, null, 1, 0, 'F', '0', '0', 'fp:group:edit', '#', 'admin', TIMESTAMP '2021-10-19 16:43:50', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2209, '删除流程分组', 2163, 5, null, null, 1, 0, 'F', '0', '0', 'fp:group:remove', '#', 'admin', TIMESTAMP '2021-10-19 16:44:12', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2210, '分组排序', 2163, 6, null, null, 1, 0, 'F', '0', '0', 'fp:group:sort', '#', 'admin', TIMESTAMP '2021-10-19 16:44:32', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2211, '查询流程定义信息', 2163, 7, null, null, 1, 0, 'F', '0', '0', 'fp:proce:query', '#', 'admin', TIMESTAMP '2021-10-19 16:44:52', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2212, '新增流程定义', 2163, 8, null, null, 1, 0, 'F', '0', '0', 'fp:proce:add', '#', 'admin', TIMESTAMP '2021-10-19 16:45:11', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2213, '修改流程定义', 2163, 9, null, null, 1, 0, 'F', '0', '0', 'fp:proce:edit', '#', 'admin', TIMESTAMP '2021-10-19 16:45:29', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2214, '删除流程定义', 2163, 10, null, null, 1, 0, 'F', '0', '0', 'fp:proce:remove', '#', 'admin', TIMESTAMP '2021-10-19 16:45:49', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2215, '停用或启用流程', 2163, 11, null, null, 1, 0, 'F', '0', '0', 'fp:proce:setStatus', '#', 'admin', TIMESTAMP '2021-10-19 16:46:10', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2216, '操作流程节点', 2163, 12, null, null, 1, 0, 'F', '0', '0', 'fp:node:insert', '#', 'admin', TIMESTAMP '2021-10-19 16:47:09', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2217, '查询流程节点信息', 2163, 13, null, null, 1, 0, 'F', '0', '0', 'fp:node:query', '#', 'admin', TIMESTAMP '2021-10-19 16:47:34', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2228, '由我参与', 2161, 6, 'bmpt', 'fp/bmpt/index', 1, 1, 'C', '0', '0', 'fp:start:bmpt', 'component', 'admin', TIMESTAMP '2021-10-23 14:19:35', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2161, '流程管理', 0, 4, 'fp', null, 1, 0, 'M', '0', '0', null, 'cascader', 'admin', TIMESTAMP '2021-09-28 17:38:49', 'admin', TIMESTAMP '2021-10-15 09:54:45', null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2190, '我的待办', 2161, 2, 'start', 'fp/start/index', 1, 1, 'C', '0', '0', 'fp:start:query', 'message', 'admin', TIMESTAMP '2021-10-12 16:08:48', null, null, null);
INSERT INTO SYS_MENU (MENU_ID, MENU_NAME, PARENT_ID, ORDER_NUM, PATH, COMPONENT, IS_FRAME, IS_CACHE, MENU_TYPE, VISIBLE, STATUS, PERMS, ICON, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2284, '查询由我参与的', 2228, 1, null, null, 1, 0, 'F', '0', '0', 'fp:start:bmpt', '#', 'admin', TIMESTAMP '2021-10-25 15:41:26', null, null, null);
新增字典数据
- 字典主表
INSERT INTO SYS_DICT_TYPE (DICT_ID, DICT_NAME, DICT_TYPE, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (262, '流程节点权限操作类型', 'fp_node_action_type', '0', 'admin', TIMESTAMP '2021-10-09 11:37:47', null, null, '流程节点权限操作类型列表');
INSERT INTO SYS_DICT_TYPE (DICT_ID, DICT_NAME, DICT_TYPE, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (260, '流程节点类型', 'fp_node_type', '0', 'admin', TIMESTAMP '2021-10-09 11:05:23', null, null, '流程节点类型列表');
INSERT INTO SYS_DICT_TYPE (DICT_ID, DICT_NAME, DICT_TYPE, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (280, '流程挂载状态', 'fp_mount_status', '0', 'admin', TIMESTAMP '2021-10-15 13:43:18', null, null, '流程挂载状态列表');
- 字典副表
INSERT INTO SYS_DICT_DATA (DICT_CODE, DICT_SORT, DICT_LABEL, DICT_VALUE, DICT_TYPE, CSS_CLASS, LIST_CLASS, IS_DEFAULT, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2719, 1, '审批人', '0', 'fp_node_type', null, null, 'N', '0', 'admin', TIMESTAMP '2021-06-26 16:24:36', null, null, '审批人');
INSERT INTO SYS_DICT_DATA (DICT_CODE, DICT_SORT, DICT_LABEL, DICT_VALUE, DICT_TYPE, CSS_CLASS, LIST_CLASS, IS_DEFAULT, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2720, 2, '抄送人', '1', 'fp_node_type', null, null, 'N', '0', 'admin', TIMESTAMP '2021-06-26 16:24:36', null, null, '抄送人');
INSERT INTO SYS_DICT_DATA (DICT_CODE, DICT_SORT, DICT_LABEL, DICT_VALUE, DICT_TYPE, CSS_CLASS, LIST_CLASS, IS_DEFAULT, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2721, 3, '服务节点', '2', 'fp_node_type', null, null, 'N', '0', 'admin', TIMESTAMP '2021-06-26 16:24:36', null, null, '服务节点');
INSERT INTO SYS_DICT_DATA (DICT_CODE, DICT_SORT, DICT_LABEL, DICT_VALUE, DICT_TYPE, CSS_CLASS, LIST_CLASS, IS_DEFAULT, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2722, 1, '同意', '0', 'fp_node_action_type', null, null, 'N', '0', 'admin', TIMESTAMP '2021-06-26 16:24:36', null, null, '同意');
INSERT INTO SYS_DICT_DATA (DICT_CODE, DICT_SORT, DICT_LABEL, DICT_VALUE, DICT_TYPE, CSS_CLASS, LIST_CLASS, IS_DEFAULT, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2723, 2, '拒绝', '1', 'fp_node_action_type', null, null, 'N', '0', 'admin', TIMESTAMP '2021-06-26 16:24:36', null, null, '拒绝');
INSERT INTO SYS_DICT_DATA (DICT_CODE, DICT_SORT, DICT_LABEL, DICT_VALUE, DICT_TYPE, CSS_CLASS, LIST_CLASS, IS_DEFAULT, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2724, 3, '转交(暂不支持)', '2', 'fp_node_action_type', null, null, 'N', '0', 'admin', TIMESTAMP '2021-06-26 16:24:36', null, null, '转交');
INSERT INTO SYS_DICT_DATA (DICT_CODE, DICT_SORT, DICT_LABEL, DICT_VALUE, DICT_TYPE, CSS_CLASS, LIST_CLASS, IS_DEFAULT, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2725, 4, '异议', '3', 'fp_node_action_type', null, null, 'N', '0', 'admin', TIMESTAMP '2021-06-26 16:24:36', null, null, '异议');
INSERT INTO SYS_DICT_DATA (DICT_CODE, DICT_SORT, DICT_LABEL, DICT_VALUE, DICT_TYPE, CSS_CLASS, LIST_CLASS, IS_DEFAULT, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2726, 1, '关闭', '0', 'fp_mount_status', null, null, 'N', '0', 'admin', TIMESTAMP '2021-06-26 16:24:36', null, null, '关闭');
INSERT INTO SYS_DICT_DATA (DICT_CODE, DICT_SORT, DICT_LABEL, DICT_VALUE, DICT_TYPE, CSS_CLASS, LIST_CLASS, IS_DEFAULT, STATUS, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK) VALUES (2727, 2, '开启', '1', 'fp_mount_status', null, null, 'N', '0', 'admin', TIMESTAMP '2021-06-26 16:24:36', null, null, '开启');